timeoutSeconds (максимум 900 секунд). Любая задача, которая не может завершиться за это время — полная повторная синхронизация, разветвление по каждой записи, сторонний API, который ограничивает вас по скорости, — должна быть разделена на более мелкие запуски.
enqueueJobs делает именно это: он просит воркеров Twenty позже запустить одну из логических функций вашего приложения, по одному разу для каждой полезной нагрузки, каждый запуск в отдельном процессе с собственным лимитом времени. Вызов возвращается немедленно.
Постановка запусков в очередь
ИмпортируйтеenqueueJobs из twenty-sdk/logic-function, укажите universalIdentifier логической функции для запуска и передайте в очередь по одной полезной нагрузке для каждого запуска.
src/logic-functions/sync-all-contacts.ts
Logic function not found, и ничего не будет поставлено в очередь. Один вызов принимает до 200 полезных нагрузок.
enqueueJobs возвращает управление, как только задания приняты, а не когда они выполнены. Он не возвращает результаты целевых функций — если вам нужно потом их прочитать, пусть каждая целевая функция запишет то, что она создаёт, в key-value store или в запись рабочего пространства.Старый помощник
enqueueJob, который добавляет в очередь одно задание за вызов, устарел. Вместо этого используйте enqueueJobs со списком payloads, состоящим из одного элемента.Параметры задания
Параметры применяются к каждому запуску в пакете.Приоритет пока нельзя настраивать. Задания в очереди всегда выполняются с самым низким приоритетом, поэтому работа платформы никогда не откладывается из‑за заданий приложений. Возможность управлять приоритетом появится скоро.
Повторная попытка при временном сбое
Twenty не выполняет повторную попытку при каждом исключении из кода приложения. Обычная вызванная ошибка считается постоянным сбоем. При временном сбое логическая функция в очереди может запросить до трёх повторных попыток, вызвавRetryableLogicFunctionError.
RetryableLogicFunctionError напрямую. Если вы расширяете его, не заменяйте его name: Twenty распознаёт сериализованное имя RetryableLogicFunctionError во всех средах выполнения.
retryCount равен 0 при первоначальном выполнении и увеличивается, только когда код приложения запрашивает повторную попытку. maxRetries не превышает 3 и может быть меньше, если у задания в очереди меньше общий лимит повторных попыток. Сбои платформы не увеличивают retryCount, хотя всё равно расходуют общий резерв безопасности очереди.
Очередь задерживает повторные попытки с экспоненциальной задержкой и случайным разбросом. Точная задержка намеренно не гарантируется, поэтому код приложения не должен зависеть от выполнения повторной попытки в точно определённое время. После достижения maxRetries ещё один RetryableLogicFunctionError фиксируется как окончательный сбой приложения без нового выполнения.
Использование: постраничный проход по длинной синхронизации
Классический шаблон — функция, которая ставит саму себя в очередь со следующим курсором. Каждый запуск обрабатывает одну страницу работы, уверенно укладываясь в собственный таймаут, а цепочка останавливается, когда больше нечего делать.src/logic-functions/sync-contacts-page.ts
Разветвление по каждой записи
Когда работа естественным образом выполняется по отдельным элементам, добавляйте в очередь по одному заданию на элемент за один вызов и позвольте воркерам обрабатывать их параллельно, вместо того чтобы перебирать элементы в цикле непосредственно в коде.Рекомендации для длительной работы
Два правила покрывают почти любое долгое задание: рекурсивный вызов вместо цикла и обработка ограниченного блока за один запуск. Запуск, который пытается сделать всё сразу, — это сценарий отказа: он упирается в таймаут и при повторной попытке начинает всё сначала с нуля. Вместо этого выберите размер блока так, чтобы он с запасом завершался в пределахtimeoutSeconds, сохраните свою позицию и поставьте в очередь следующий запуск.
src/logic-functions/enrich-companies-batch.ts
- Размер блока выбирайте, исходя из самого медленного элемента, а не среднего.
CHUNK_SIZE × время обработки в худшем случаедолжно помещаться вtimeoutSecondsс запасом, иначе хвост блока будет потерян, когда запуск обрежет таймаут. - Сделайте условие завершения явным. Вызывайте рекурсивно только пока вернулся полный блок. Цепочка, которая останавливается только на основе «нет результатов», будет продолжаться бесконечно, если источник когда‑либо вернёт укороченную страницу посередине.
- Сохраняйте прогресс перед постановкой в очередь следующего запуска, чтобы при сбое звена цепочки она возобновлялась с последнего завершённого блока, а не с начала.
- Сделайте каждый блок идемпотентным. Повторная обработка одного блока после повторной попытки не должна приводить к двойной записи — привязывайте операции записи к идентификатору обрабатываемой записи или к внешнему идентификатору.
- Отдавайте предпочтение цепочке из блоков перед одним гигантским разветвлением, когда работа обращается к внешнему сервису с ограничением по скорости: цепочка с
delayMsсаморегулирует темп, тогда как тысячи заданий, поставленных в очередь одновременно, сразу становятся допустимыми к выполнению.