Best practices for writing well-behaving Jobs in your codebase
This guide assumes you already have a project setup and working with Trigger.dev. If not, head over to our Quick Start guides to get up and running in a few minutes.
A Job is a collection of Tasks that are run in a specific order. You can think of it as a function that you can run on a schedule, or when an event happens. Jobs are defined by calling the TriggerClient.defineJob
function
If you aren’t seeing defined jobs in your Trigger.dev dashboard, it might be because the job file isn’t being imported in your app.
Each job must have a unique and stable id
and name
. The id
is used to identify the Job in the database, and the name
is used to identify the Job in the UI.
We will pass the value of the id
property through a slugifier because we use it in URLs in our Dashboard. This means you can use any characters you want, but we recommend using only lowercase letters, numbers and dashes.
The version
property is used to track changes to your Job. It’s required to be a semantic version string. You can track changes to your Job by incrementing the version number, and we will display in the Dashboard which version each Job Run was created with.
The trigger you choose determines how and when a job will run. See our Triggers guide for more information. The Trigger you choose also defines the type of the run payload
argument (more in this below)
Integrations provide a convienent way to create and run tasks against authenticated APIs inside your Job’s run function. You’ll need to pass them in the integrations
option when defining your Job.
The run
function implements your custom code that will be executed when your Job is run. It’s an async function that takes three arguments:
payload
- The type of the payload
argument is determined by the Trigger you choose.IO
, which exposes built-in tasks and allows you to create your own, as well as interact with integrations.context
object, which contains information about the current run, such as the run ID, the Job ID, and the Job version. Context referenceWe do not compile and ship your code to run on the Trigger.dev server. It runs exactly where you’ve deployed your code (e.g. Vercel).
The run
function you define is like a normal JavaScript function in all respects except one: it will be called one or more times to complete a single Job Run.
This means that you can’t rely on any state that is not persisted between runs, and you must create tasks to ensure that work is not repeated.
Why does the run function work like this?
The run function is called multiple times to ensure that your Job is resilient to failure and can finish running even if it is interrupted. There are many reasons why a run could be interrupted and resumed later, including:
Tasks are so important that we’ve dedicated a whole section to them. See our Tasks guide for more information.
We provide some built-in tasks that you can use in your run function:
Task | Description | Task code |
---|---|---|
Delay | Wait for a period of time | await io.wait("wait", 60); |
Log | Log a message | await io.logger.log("Hello"); |
Send Event | Send an event (for eventTrigger) | await io.sendEvent("my-event", { name: "my.event", payload: { hello: "world" } }); |
Background fetch | Fetch data from a URL that can take longer that the serverless timeout. | await io.backgroundFetch("fetch-some-data", { url: "https://example.com" }); |
For a full list of built-in Tasks, see the io SDK reference. The below example makes use a few of these built-in tasks:
You can also create your own tasks or use tasks provided by our integration packages. See Creating Tasks for more information. The example below demonstrates creating tasks in 3 different ways:
If your run function throws an error, the Job Run will fail and the error will be displayed in the Dashboard. If you’d like to retry on an error, you can do so using tasks and the retry
option.
See the retry options for more information.
We will throw some errors internally to interrupt run execution so they can be resumed later. If you put a try/catch
block in your run code and catch these errors, your job will not work correctly. You can check if an error is an internal error using isTriggerError():
Alternatively, you can use the io.try() function:
If you want to create tasks in a loop, you should use for const ... of
to ensure that the tasks are created in the correct order.
We don’t currently support running tasks in parallel so Promise.all
will not work correctly.
This is something on our roadmap that we hope to support soon.
Anything you return from the run
function will be automatically set as the run output and displayed in the Dashboard.
We recommend exploring all of the below sections to fully understand how to create and run Jobs using Trigger.dev.
A guide for how to run your Jobs. Triggering a test Run and Triggering your Job for real
Integrations make it easy to authenticate and use APIs. Learn how to use and create integrations.
Find code examples for many popular APIs. These can be copied / modified for use in your own projects.
How to use the SDK. This includes all the available Tasks, triggers and actions you can use.