Раздел 46 · Effect: Тихая Академия

Босс: честный Почтамт

middle-senior~80 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Утренняя трасса из прошлого урока лежит на столе. Книгу спросили про три башни, она ответила про две. Третью, T-5, пачка из этапа 11 по своему правилу назвала несуществующей: её не было в ответе. А на T-5 живёт Ринцвальд.

Пондер нашёл, в чём дело. У книги Магистрали есть второй ответ, GET /towers/checked, и в нём два списка: башни, до которых книга дозвонилась, и башни, до которых нет. Старый ответ второй список молча выбрасывал. Почтамт с первого дня читал только первую половину правды, а Магистраль так отвечала всем уже год.

Новых модулей Effect сегодня нет. Есть журнал из урока 98, трасса из урока 99, счётчики из урока 100, пачки и кэш из урока 101 и Почтамт из урока 97. Их надо сложить в одну книгу, которой можно верить, и в Почтамт, который не врёт горожанам.

Что нужно Почтамту

Тесты накопительные: идут все прошлые этапы, а сверху новый модуль src/honest.ts.

  • Книга, которой верят только проверенное. honestBook(baseUrl) спрашивает /towers/checked пачкой, как этап 11. Башня в ответе: ответ. Башня в списке недозвона: беда книга не проверила. Башни нет нигде: нет такой башни.
  • Срок ответа. Пачка ждёт книгу две секунды. Дольше это книга не отвечает у каждого вопроса пачки.
  • Кэш только правды. Ответ живёт минуту. Беда не живёт вовсе: про ту же башню книгу спросят снова.
  • Всё видно. Поверх книги журнал, трасса и счётчики: недозвон пишется в журнал как Warn, закрывает спан провалом и прибавляет единицу к своему счётчику.
  • Горожанину правду. «Нет такой башни» остаётся ответом 422. Любая другая беда книги становится 503 с причиной: новая проблема BookUnavailable на HttpApiError.Problem из урока 91.
  • Почтамт целиком. PostOfficeHonest({ towersUrl, archiveDir }) собирается как PostOfficeLive, только окошко писем проверяет адрес честно, а книга башен честная. Снаружи ему нужны те же провод, книги, файлы и пути.

Чек-лист перед сдачей

  1. Тесты всех прошлых этапов зелёные.
  2. Три письма разом: один запрос к книге.
  3. Повторное письмо на ту же башню: ни одного запроса.
  4. Недозвон: 503 с tower и reason, письмо не принято, следующий вопрос снова идёт к книге.
  5. Молчание книги: 503 через две секунды, а не вечная очередь.
  6. Недозвон в журнале, в трассе и в счётчике.
  7. Выдача писем работает на честной книге.

Почтамт, этап 12

Подумай до кода

  • Куда ставить срок. На вопрос одной башни или на запрос пачки? В пачке вопросы разных писем. Если книга молчит, ждать две секунды должен каждый из них или все вместе один раз?
  • Что кэшировать. В уроке 101 ответ жил минуту, беда не жила. Почему недозвон тем более нельзя кэшировать? Что услышат горожане минуту спустя, если книга уже дозвонилась?
  • Порядок обёрток. loggedBook, tracedBook и meteredBook принимают книгу и отдают книгу, их можно надеть в любом порядке. Тест ждёт журнал и счётчик у каждого вопроса, а не у каждой пачки. Где тогда должен быть кэш: снаружи обёрток или внутри? Сколько строк журнала даст вопрос, который ответил кэш?
  • Ошибка, которой нет в договоре. Окошко send в договоре знает только UnknownAddress. BookUnavailable там нет, и вписать её туда нельзя: старый договор не переписывают. Но сервер отдаёт проблему с её статусом, даже если она пришла дефектом. Чем это лучше голого 500 из урока 97 и чем хуже настоящей ошибки в договоре?

Тест собирает Почтамт так, как его соберёт Гекс, только слои снаружи свои: провод к книге Гилта подменён, база это PGlite в памяти, подвал это карта строк, журнал пишет в массив, спаны ловит трассировщик в памяти.

const App = HttpApiBuilder.layer(PostOfficeApi).pipe(
  Layer.provide(PostOfficeHonest({ towersUrl: 'http://book.ankmor', archiveDir: '/srv/pochtamt' })),
  Layer.provide(
    Layer.mergeAll(
      Magistral,
      PgliteClient.layer(),
      MemoryFs,
      Path.layer,
      HttpServer.layerServices,
      journalLayer((entry) => journal.push(entry)),
      MemoryTracer,
    ),
  ),
);

const { handler, dispose } = HttpRouter.toWebHandler(App);

journalLayer и MemoryTracer стоят снаружи, рядом с проводом и базой. Почтамт не знает, куда пишется его журнал и кто собирает его спаны: в проде здесь встанут логгер в файл и экспорт трасс, а PostOfficeHonest не изменится.

Нестабильно. Окошки Почтамта стоят на effect/http и effect/http-api: HttpApiError.Problem, HttpApiBuilder и HttpRouter.toWebHandler в 4.1 помечены @stability unstable. Журнал, трассы, счётчики, RequestResolver и Cache стабильны. Урок написан на 4.1.0.

Сюжетный квест

Третья, последняя улика квеста «Проглоченная ошибка Гилта». Первые две лежат в боссе обработчика кадров и в боссе ретранслятора. Найдёшь все три, и на дашборде квест раскроется.

Практика

Глубже в архиве

Сроки, повторы и предохранители для зависимостей, которые отвечают медленно или не отвечают вовсе, разобраны в уроке про паттерны устойчивости раздела про бэкенд.

Итог

Через неделю трасса лежит на столе Патриция. Не одна, а все за неделю, и рядом выписка из книги Магистрали за год, которую Пондер поднял по ответу /towers/checked: каждый недозвон, который в старом ответе пропадал без следа, а в отчёте Магистрали становился зелёной строкой «башня проверена». Напротив Патриция сидит Гилт. Отчёт у него в руках тоже зелёный.

Больше Патриций ничего не говорит. Рыдкулл выходит из дворца с бумагой, на которой стоит печать Казимира: Академия получает звание лекторов. Ранг за этот заказ: лектор недавних рун.

Дальше

Утром в лавке напротив Почтамта лавочница Чонси вешает на витрину большой лист: все сорок башен города, у каждой отметка «открыта», «закрыта» или «книга не дозвонилась», и время последней проверки. Горожане останавливаются у витрины чаще, чем у окошек. Им больше не нужно верить ни Магистрали, ни Почтамту: они хотят видеть сами.

Следующий раздел курса это EF13 «Витрина»: Effect в браузере, состояние на атомах и страница, которая сама следит за башнями. Начинается он с урока 103.