timeoutSeconds (900 seconds maximum). Anything that can’t finish in that window — a full re-sync, a per-record fan-out, a third-party API that rate-limits you — has to be split into smaller runs.
enqueueJob does exactly that: it asks the Diex workers to run one of your app’s logic functions later, in its own process, with its own timeout budget. The caller returns immediately.
Enqueue a run
ImportenqueueJob from diex-sdk/logic-function and point it at the universalIdentifier of the logic function you want to run.
src/logic-functions/sync-all-contacts.ts
payload as its handler argument, exactly like any other trigger. It must belong to the same application as the caller — enqueuing another app’s function is rejected with Logic function not found.
enqueueJob returns as soon as the job is accepted, not when it has run. It does not return the target’s result — have the target write what it produces to the key-value store or to a workspace record if you need to read it back.Job options
Priority is not configurable yet. Enqueued jobs always run at the lowest priority, so platform work is never delayed behind application jobs. Control over priority is coming soon.
Retry a transient failure
Diex does not retry every exception from application code. An ordinary thrown error is treated as a permanent failure. For a transient failure, a queued logic function can request up to three retries by throwingRetryableLogicFunctionError.
RetryableLogicFunctionError directly when possible. If you extend it, do not replace its name: Diex recognizes the serialized name RetryableLogicFunctionError across execution runtimes.
retryCount is 0 for the initial execution and increases only when application code requests a retry. maxRetries is at most 3 and can be lower when the queued job has a smaller overall retry limit. Platform failures do not increase retryCount, although they still consume the queue’s overall safety budget.
The queue delays retry attempts with exponential backoff and jitter. The exact delay is intentionally not guaranteed, so application code should not depend on a retry happening at a precise time. Once maxRetries is reached, another RetryableLogicFunctionError is recorded as the final application failure without another execution.
Use it: page through a long sync
The classic shape is a function that enqueues itself with the next cursor. Each run does one page of work well inside its own timeout, and the chain stops when there is nothing left.src/logic-functions/sync-contacts-page.ts
Fan out per record
When the work is naturally per-item, enqueue one job per item and let the workers process them in parallel instead of looping inline.Good practice for long-running work
Two rules cover almost every long job: recurse instead of looping, and process a bounded chunk per run. A run that tries to do everything is the failure mode — it hits the timeout, and with a retry it starts the whole thing again from zero. Instead, size one chunk so it comfortably finishes insidetimeoutSeconds, persist your position, and enqueue the next run.
src/logic-functions/enrich-companies-batch.ts
- Size the chunk from the slowest item, not the average.
CHUNK_SIZE × worst-case item timehas to fit intimeoutSecondswith room to spare, or the tail of a chunk is lost when the run is cut off. - Make the terminating condition explicit. Recurse only while a full chunk came back. A chain that stops on “no results” alone will keep going forever if the source ever returns a short page mid-way.
- Persist progress before enqueuing the next run, so a failed link restarts from the last completed chunk instead of the beginning.
- Keep each chunk idempotent. Reprocessing one chunk after a retry must not double-write — key writes on the record or external id you are processing.
- Prefer a chunked chain over one giant fan-out when the work hits a rate-limited third party: a chain with
delayMspaces itself, whereas thousands of jobs enqueued at once all become eligible immediately.