Files
huncode 6c4f980f51
Build and deploy / deploy (push) Successful in 14s
revise June 2020 idempotency articles
2026-07-31 11:32:33 +03:00

146 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Июнь 2020 — тройное ревью автономного пакета P28 «Повторы запросов и идемпотентность»
Статус: **принят в publication registry 31 июля 2026 года**. Ревизии
накладываются по стабильным slug, сохраняют дату и автора базового архива и
не перезаписывают <code>articles.json</code>.
Проверенные revision:
- <code>editorial-2020-06-practice-retry-idempotency</code>;
- <code>editorial-2020-06-mechanism-retry-idempotency</code>;
- <code>editorial-2020-06-field-retry-idempotency</code>.
Модуль экспортирует ровно три revision. В объектах нет <code>date</code> и
<code>author</code>, поэтому будущий publication layer должен сохранить
стабильные дату и автора из базового архива. При запуске
<code>--print-revisions</code> stdout содержит только JSON; отдельная
<code>--verify-fixture</code> печатает результат учебной in-memory проверки.
## Проход 1. Факты, механизм и ограничения — пройдено
| Утверждение или решение | Первичный / официальный источник | Проверенная граница |
| --- | --- | --- |
| HTTP различает идемпотентные методы и <code>POST</code>; <code>409</code>, <code>503</code> и <code>Retry-After</code> не создают idempotency сами по себе | [RFC 7231](https://www.rfc-editor.org/rfc/rfc7231.html) | Статьи не называют любой POST безопасным для автоповтора и не приписывают одному status универсальную retry-policy. |
| Идея key, fingerprint, replay завершённой операции и конфликта параллельного повтора уже была описана в начале 2020 года | [draft-idempotency-header-01](https://datatracker.ietf.org/doc/html/draft-idempotency-header-01) | Документ назван историческим work in progress, не готовым стандартом и не причиной считать header универсально поддержанным. |
| Timeout клиентского HTTP-request не отменяет серверный business effect автоматически | [Node.js v12: ClientRequest.setTimeout](https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_request_settimeout_timeout_callback) | Все timeout в статьях описаны как неизвестный исход для наблюдающей стороны, а не как rollback. |
| Уникальный scope и атомарный захват записи должны жить в устойчивом хранилище | [PostgreSQL 12: Constraints](https://www.postgresql.org/docs/12/ddl-constraints.html), [INSERT / ON CONFLICT](https://www.postgresql.org/docs/12/sql-insert.html) | Учебная SQL-схема не выдаёт процессную память за защиту от двух процессов и отделяет внутреннюю транзакцию от внешнего effect. |
Технический разбор проверен повторно после редакторских правок:
- key имеет scope <code>actor + operation + key</code>, а fingerprint
отделяет retry того же payload от другой команды;
- <code>completed</code> хранит минимальный terminal response для replay;
<code>in_progress</code> и mismatch payload останавливают второй handler до
business effect;
- для эффекта внутри одной базы учебный пример сохраняет объект и terminal
запись в одной транзакции;
- для внешнего вызова текст прямо требует отдельный устойчивый key либо status
route и не обещает exactly once локальной таблицей;
- retention key должен быть длиннее документированного retry-budget. Удаление
<code>in_progress</code> не показано как средство исправить сбой.
Выполнена автономная фикстура <code>--verify-fixture</code>. Реальный вывод
подтверждает: первая доставка имеет <code>response_lost</code>, создан ровно
один effect, retry возвращает сохранённый <code>demo-request-42</code>, а тот
же key с другой hash получает <code>409</code>. Фикстура не открывает сеть,
базу, proxy или внешний API.
Все адреса, ключи, payload, result ID, журналы и тайминги учебные:
<code>api.training.invalid</code>, <code>127.0.0.1:48080</code>,
<code>demo-key-retry-2020-06-a7f1</code> и <code>demo-request-42</code>. Нет
реальных платёжных данных, credentials, endpoint или утверждения о production
инциденте.
Вердикт прохода: **пройден**. Исторические источники и пример согласованы;
механика ограничена тем, что пакет действительно проверяет.
## Проход 2. Редактура, голос М3 и объём — пройдено
| Revision | Проблема и цена в первых двух абзацах | Главный вопрос | Голос и следующее действие |
| --- | --- | --- | --- |
| Практика | Потерянный ответ приводит к двойной заявке и ручной чистке | Как удержать один intent, key и конечный retry-budget на стороне клиента | М3 связывает UI с API-contract; маршрут вводит key до первой попытки и проверяет «response lost → replay». |
| Механизм | Два POST конкурируют, а boolean не объясняет состояние результата | Как сохранить scope, fingerprint и terminal response в устойчивом хранилище | М3 связывает HTTP с SQL-границей, но не выдаёт локальную таблицу за глобальную exactly-once гарантию. |
| Полевой разбор | Один timeout скрывает три разных пути и провоцирует blind retry | Как собрать requestId, key, журнал и временной budget в одну проверку | М3 связывает frontend, edge и backend через учебную трассу без современного observability stack. |
- Draft gate после финальной правки измерил основной текст без источников:
практика — **10 899** знаков, механизм — **11 577**, полевой разбор —
**11 331**. Все три текста лежат в диапазоне 5 000–15 000 знаков.
- В каждом материале проблема и цена названы в первых двух абзацах. Затем
сохранена короткая последовательность «симптом → причина → проверка →
действие», а не общая речь о надёжности.
- У каждой revision есть не менее пяти смысловых разделов, таблица с
<code>caption</code>/<code>thead</code>, figure с осмысленными
<code>alt</code>/<code>figcaption</code>, HTTP/code/log example,
нумерованный маршрут и минимум две первичные или официальные ссылки.
- Удалены поздние для автора 2020 года обобщения: нет payment API как основы
примера, event streaming, SLO, распределённой трассировки или фальшивого
опыта крупного production-инцидента. Внешний effect, proxy и база названы
границами, которые ещё нужно проверить в конкретном проекте.
Вердикт прохода: **пройден**. Тексты плотные, прагматичные и соответствуют
М3 / июню 2020 года.
## Проход 3. Визуал и выпуск автономного пакета — пройдено в заданных границах
- <code>retry-idempotency-request-path-2020.svg</code> показывает один intent,
первую доставку, потерянный ответ и replay. Он объясняет, почему timeout не
создаёт право послать новый key.
- <code>retry-idempotency-state-contract-2020.svg</code> показывает scope,
атомарный захват записи, ветки <code>completed</code>/<code>conflict</code>
и отдельную границу внешнего effect.
- <code>retry-idempotency-diagnosis-2020.svg</code> показывает разные
<code>requestId</code> попыток и общий idempotency key на временной шкале.
- У SVG есть <code>title</code>, <code>desc</code>, <code>role="img"</code>,
вертикальные viewBox, контрастные карточки и короткие подписи. Нет
JavaScript, <code>foreignObject</code>, внешних URL или растровых data URI.
- Диаграммы отрендерены через Sharp при ширине **375 px**. Независимый
визуальный проход обнаружил слишком длинные нижние подписи во второй и
третьей схеме; подписи сокращены и разбиты на строки. Финальные 375 px PNG
прочитаны повторно: обрезания, наложения и горизонтальный overflow внутри
SVG не обнаружены.
- Основной редактор отдельно просмотрел финальные raster-версии на 375 px и
подтвердил вывод. После подключения registry strict audit и production build
пройдены; они не подменяют реальный HTTP, PostgreSQL или внешний effect.
### Фактические команды и результаты
<pre><code>cd web
node --check scripts/upgrade-2020-06.mjs
npm run audit:draft -- scripts/upgrade-2020-06.mjs
node scripts/upgrade-2020-06.mjs --verify-fixture
xmllint --noout \
public/assets/editorial/2020/retry-idempotency-request-path-2020.svg \
public/assets/editorial/2020/retry-idempotency-state-contract-2020.svg \
public/assets/editorial/2020/retry-idempotency-diagnosis-2020.svg</code></pre>
| Проверка | Реальный результат |
| --- | --- |
| <code>node --check</code> | код завершения 0 |
| Draft audit | PASS: 10 899 / 11 577 / 11 331 знаков тела |
| In-memory fixture | <code>effects = 1</code>; четыре логические проверки вернули <code>true</code> |
| XML | все три SVG валидны, код завершения 0 |
| 375 px visual preflight | выполнен после финальной правки; читаемость и границы подтверждены локальным Sharp-рендером |
| Strict audit после подключения registry | PASS: 10 899 / 11 577 / 11 331 знаков; 2 / 2 / 2 table и 3 / 2 / 3 code example |
| <code>npm run build</code> | PASS, code 0, 374 статические страницы |
| Scope/self-review | PASS: в revision нет <code>date</code>/<code>author</code>, <code>articles.json</code> не перезаписан |
Не запускались browser-review опубликенной страницы, proxy, PostgreSQL,
curl-команды, интеграционный стенд или production deployment. Учебный маршрут
не выдан за опубликованную HTTP-функциональность.
Проверка assistive technology также не заявляется; у рисунков есть
структурные alt-тексты и подписи, но это не заменяет реальную проверку
скринридером.
## Итог
Статус: **тройное ревью пройдено, пакет принят к публикации**.
Изменения после трёх проходов:
1. SQL-псевдокод механизма приведён к тексту: внутренний effect и terminal
idempotency record показаны внутри одной учебной транзакции.
2. Две длинные мобильные подписи SVG сокращены и разбиты так, чтобы сохранить
крупный шрифт в 375 px.
3. Registry заменяет только редакционные поля по стабильному slug; архив,
standard, очередь и package configuration не перезаписаны.