Отложенные касания
Как агент планирует работу на потом и возвращает результат в тот канал, откуда пришёл запрос, — надёжные задачи, атомарный захват и восстановление.
Кое-что нельзя выяснить внутри хода: проверку, которая займёт минуты, напоминание на следующий вторник, разговор о продлении, который нужно начать через полтора месяца. Агент может зарегистрировать такую работу и позволить ответу прийти тогда, когда он будет готов.
Как это устроено
Прямо посреди хода агент вызывает schedule_followup для работы, которая внутри хода не закончится:
проверка на несколько минут, напоминание на следующий вторник, разговор о продлении через полтора
месяца.
Задача — это строка в Postgres, а не сообщение в брокере. Задача в ожидании — зафиксированные данные, поэтому передеплой или падение её не теряют: надёжность достаётся бесплатно от уже используемого хранилища.
Опросчик просыпается раз в несколько секунд и ищет задачи, которым пришло время. Плата за это — точность: задача срабатывает на ближайшем опросе, а не с точностью до миллисекунды, что для касаний с горизонтом от минут до недель потерей не является.
Наступившие задачи захватываются через FOR UPDATE SKIP LOCKED. Одному опросчику это не нужно — но
написанное правильно сейчас означает, что второй экземпляр потом не сможет отправить дважды, а
доставленное дважды касание стоит доверия клиента к отправителю.
Результат формируется. Задача, захваченная процессом, который затем умер, возвращается в ожидание процедурой восстановления, а не висит «в работе» вечно.
Доставка идёт обратно в тот канал, откуда пришёл запрос: пузырём в веб-виджете, сообщением в Telegram или WhatsApp. Кто спросил в WhatsApp, тому в WhatsApp и ответят.
Инструмент возвращает управление сразу — клиент получает свой ответ сейчас, а отложенный результат позже.
Инструмент не блокирует ход. Он пишет строку и возвращает управление, поэтому клиент получает свой ответ сейчас, а отложенный результат — позже.
Почему очередь — это таблица в базе
Ни Redis, ни брокера. Задачи — строки в Postgres, и это осознанный размен:
- Перезапуски не теряют работу. Задача в ожидании — зафиксированная строка. Процесс можно передеплоить прямо на лету, и опросчик подхватит задачу, вернувшись в строй: надёжность достаётся бесплатно вместе с уже используемым хранилищем, а не приходит от второй системы с её собственными режимами отказа.
- Одной системой в эксплуатации меньше. Для однопроцессного развёртывания цикла опроса достаточно.
Плата — точность по времени: задача срабатывает на ближайшем опросе, а не с точностью до миллисекунды. Для касаний с горизонтом от минут до недель это не потеря.
Захват атомарен
Наступившие задачи захватываются через FOR UPDATE SKIP LOCKED. Одному опросчику это заведомо не нужно
— но написанное правильно сейчас означает, что запуск второго экземпляра потом не приведёт к двойной
отправке. Дважды доставленное касание — не косметический баг: это клиент, дважды получивший «пора
продлевать» и потерявший доверие к отправителю.
SKIP LOCKED заодно означает, что медленная задача не держит очередь за собой: другие обработчики
перешагивают заблокированную строку и берут следующую.
Восстановление
Задача, захваченная процессом, который затем умер, иначе висела бы «в работе» вечно. Процедура восстановления возвращает застрявшие задачи в ожидание, чтобы они были повторены, а не тихо потеряны.
Доставка идёт туда, откуда пришёл запрос
Результат возвращается в тот канал, откуда пришёл запрос, а не в канал по выбору платформы. Кто спросил в WhatsApp, тому в WhatsApp и ответят. Собственные плановые касания тенанта — напоминания о продлении, дожим по срокам — работают так же, с той периодичностью, которую вы настроите.
Что это даёт на практике
- Агент может сказать «я вернусь к вам с этим» — и действительно вернуться.
- Напоминания переживают деплой, перезапуск и падение.
- Касание доставляется один раз и находит человека там, где он с вами разговаривал.
Деловой аргумент в пользу касаний, которые не зависят от чьей-то памяти, — на странице Высвобожденное время, а планирование — один из встроенных инструментов, описанных в статье Инструменты и MCP.