Как это устроено

Отложенные касания

Как агент планирует работу на потом и возвращает результат в тот канал, откуда пришёл запрос, — надёжные задачи, атомарный захват и восстановление.

Кое-что нельзя выяснить внутри хода: проверку, которая займёт минуты, напоминание на следующий вторник, разговор о продлении, который нужно начать через полтора месяца. Агент может зарегистрировать такую работу и позволить ответу прийти тогда, когда он будет готов.

Как это устроено

1. Регистрация

Прямо посреди хода агент вызывает schedule_followup для работы, которая внутри хода не закончится: проверка на несколько минут, напоминание на следующий вторник, разговор о продлении через полтора месяца.

2. Сохранение

Задача — это строка в Postgres, а не сообщение в брокере. Задача в ожидании — зафиксированные данные, поэтому передеплой или падение её не теряют: надёжность достаётся бесплатно от уже используемого хранилища.

3. Опрос

Опросчик просыпается раз в несколько секунд и ищет задачи, которым пришло время. Плата за это — точность: задача срабатывает на ближайшем опросе, а не с точностью до миллисекунды, что для касаний с горизонтом от минут до недель потерей не является.

4. Захват

Наступившие задачи захватываются через FOR UPDATE SKIP LOCKED. Одному опросчику это не нужно — но написанное правильно сейчас означает, что второй экземпляр потом не сможет отправить дважды, а доставленное дважды касание стоит доверия клиента к отправителю.

5. Выполнение

Результат формируется. Задача, захваченная процессом, который затем умер, возвращается в ожидание процедурой восстановления, а не висит «в работе» вечно.

6. Доставка

Доставка идёт обратно в тот канал, откуда пришёл запрос: пузырём в веб-виджете, сообщением в Telegram или WhatsApp. Кто спросил в WhatsApp, тому в WhatsApp и ответят.

Инструмент возвращает управление сразу — клиент получает свой ответ сейчас, а отложенный результат позже.

Инструмент не блокирует ход. Он пишет строку и возвращает управление, поэтому клиент получает свой ответ сейчас, а отложенный результат — позже.

Почему очередь — это таблица в базе

Ни Redis, ни брокера. Задачи — строки в Postgres, и это осознанный размен:

  • Перезапуски не теряют работу. Задача в ожидании — зафиксированная строка. Процесс можно передеплоить прямо на лету, и опросчик подхватит задачу, вернувшись в строй: надёжность достаётся бесплатно вместе с уже используемым хранилищем, а не приходит от второй системы с её собственными режимами отказа.
  • Одной системой в эксплуатации меньше. Для однопроцессного развёртывания цикла опроса достаточно.

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

Захват атомарен

Наступившие задачи захватываются через FOR UPDATE SKIP LOCKED. Одному опросчику это заведомо не нужно — но написанное правильно сейчас означает, что запуск второго экземпляра потом не приведёт к двойной отправке. Дважды доставленное касание — не косметический баг: это клиент, дважды получивший «пора продлевать» и потерявший доверие к отправителю.

SKIP LOCKED заодно означает, что медленная задача не держит очередь за собой: другие обработчики перешагивают заблокированную строку и берут следующую.

Восстановление

Задача, захваченная процессом, который затем умер, иначе висела бы «в работе» вечно. Процедура восстановления возвращает застрявшие задачи в ожидание, чтобы они были повторены, а не тихо потеряны.

Доставка идёт туда, откуда пришёл запрос

Результат возвращается в тот канал, откуда пришёл запрос, а не в канал по выбору платформы. Кто спросил в WhatsApp, тому в WhatsApp и ответят. Собственные плановые касания тенанта — напоминания о продлении, дожим по срокам — работают так же, с той периодичностью, которую вы настроите.

Что это даёт на практике

  • Агент может сказать «я вернусь к вам с этим» — и действительно вернуться.
  • Напоминания переживают деплой, перезапуск и падение.
  • Касание доставляется один раз и находит человека там, где он с вами разговаривал.

Деловой аргумент в пользу касаний, которые не зависят от чьей-то памяти, — на странице Высвобожденное время, а планирование — один из встроенных инструментов, описанных в статье Инструменты и MCP.