Добавьте progress, cancellation, notifications и cache
Production-клиент отличается от демо тем, что управляет неидеальными сценариями. Он ограничивает время, отменяет ненужную работу, показывает прогресс, обновляет discovery по notifications и кэширует результаты по server hints. Каждый из этих механизмов кажется мелочью, пока не окажется, что без него система либо висит, либо отдаёт устаревшие данные.
Кэш начинается с честного ключа - он должен включать authorization context, иначе приватные данные утекут между пользователями.
cacheKey = authorizationContext + method + normalizedParams
if result.cacheScope === "public":
shared cache допустим только для действительно общих данных
if result.cacheScope === "private":
cache изолирован по токену/tenant/user
expiresAt = receivedAt + result.ttlMs
list_changed => invalidate затронутую коллекциюОтмена тоже требует дисциплины: сигнал доходит до сервера, тот перестаёт слать progress, но уже совершённый побочный эффект сам не откатывается.
host aborts user request
├─ stdio: send notifications/cancelled for request id
└─ HTTP: abort request stream
server checks signal between expensive steps
server stops emitting progress
domain side effect is not rolled back automaticallyСобрать все четыре механизма вместе помогает таблица - зачем каждый и где его главная оговорка.
Механизм · Зачем · Главная оговорка
- Progress - UX и watchdog для долгого call; Не является durable task history
- Cancellation - Остановить ненужное вычисление; Не отменяет уже committed side effect
- List-changed - Инвалидировать discovery cache; Modern HTTP требует listen subscription
ttlMs- Freshness hint; 0 означает stale, не "запрет cache"cacheScope- Public/private reuse boundary; Server отвечает за правдивую классификацию
Оговорки здесь важнее самих механизмов. Progress - это UX и watchdog, а не durable-история задачи. Cancellation останавливает вычисление, но не отменяет committed side effect. list_changed инвалидирует discovery-кэш, но в современном HTTP требует listen-subscription. А ttlMs: 0 означает "данные stale", а не "кэш запрещён".
Cancel не равен rollback. Если инструмент отправил платёж, письмо или деплой, отмена протокольного запроса не возвращает систему назад. Idempotency, commit status и reconciliation проектируются на уровне домена - протокол здесь бессилен по определению.
Прогресс и отмена - это ещё не настоящая длинная работа. Когда операции нужен дополнительный ввод или она идёт минутами, в дело вступают явные механизмы: MRTR и tasks.