* Started building out the docs navigation

* Drafted out a lot of the docs pages. With just titles and descriptions with a coming soon message for now.

* A ton more scaffolded pages with titles, descriptions, coming soon/incomplete docs messages

* Created the remaining page stubs

* Introduction page improvements

* Lots of docs changes, mostly the task overview page

* Moved some bits around

* Task overview fleshed out

* Triggering docs page

* Regular task page

* CLi dev docs

* Docs for debugging locally

* Environment variables docs

* Added env var images

* Deployment guides

* Updated the title of “Integrations” to “Deployment integrations” to make it less confusing

* Lots more docs pages

* Changed the language to JavaScript

* Fixed typos about queues and added a simple code sample

* Moved the local debugger docs into the CLI dev page

* Added the CLI deploy options

* Delete the local debugger page

* Updated the logging page with structured logging

* Added the new CLI deploy options

* Change to h4 for one of the options

* Errors page

* WIP on retrying

* Retrying guide

* Wait docs pages

* Queuing docs simplified, partial written

* Queuing and concurrency docs

* Run tests docs

* New combined error and retrying page

* Errors and retrying page updated

* More docs

* Added a possible configurations coming soon table

* Created a limits page

* Added warnings about how you need to get early access

* Minor fixes for the docs
This commit is contained in:
Matt Aitken
2024-03-22 14:09:27 +00:00
committed by GitHub
parent cf9d466b9e
commit de302858f8
102 changed files with 2312 additions and 4 deletions
@@ -0,0 +1,21 @@
name: OpenTelemetry Auto-Instrumentation Request
description: Suggest an SDK that you'd like to be auto-instrumented in the Run log view
title: "auto-instrumentation: "
labels: ["🌟 enhancement"]
body:
- type: textarea
attributes:
label: What API or SDK would you to have automatic spans for?
description: A clear description of which API or SDK you'd like, and links to it.
validations:
required: true
- type: textarea
attributes:
label: Is there an existing OpenTelemetry auto-instrumentation package?
description: You can search for existing ones https://opentelemetry.io/ecosystem/registry/?component=instrumentation&language=js
validations:
required: true
- type: textarea
attributes:
label: Additional information
description: Add any other information related to the feature here. If your feature request is related to any issues or discussions, link them here.
+1
View File
@@ -0,0 +1 @@
<Warning>This feature will become available during the Developer Preview.</Warning>
+3
View File
@@ -0,0 +1,3 @@
<Warning>This feature will become available during the Developer Preview.</Warning>
To get the latest updates on the Developer Preview, [join our Discord community](https://trigger.dev/discord) or follow us on [Twitter](https://twitter.com/triggerdotdev).
+1
View File
@@ -0,0 +1 @@
<Note>This documentation is coming soon.</Note>
+34
View File
@@ -0,0 +1,34 @@
```ts /trigger/openai.ts
import { task } from "@trigger.dev/sdk/v3";
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export const openaiTask = task({
id: "openai-task",
//specifying retry options overrides the defaults defined in your trigger.config file
retry: {
maxAttempts: 10,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
randomize: false,
},
run: async (payload: { prompt: string }) => {
//if this fails, it will throw an error and retry
const chatCompletion = await openai.chat.completions.create({
messages: [{ role: "user", content: payload.prompt }],
model: "gpt-3.5-turbo",
});
if (chatCompletion.choices[0]?.message.content === undefined) {
//sometimes OpenAI returns an empty response, let's retry by throwing an error
throw new Error("OpenAI call failed");
}
return chatCompletion.choices[0].message.content;
},
});
```
@@ -0,0 +1,4 @@
<Note>
In the Trigger.dev Cloud we automatically pause execution of tasks when they are waiting for
longer than a few seconds. You are not charged when execution is paused.
</Note>
+1 -4
View File
@@ -8,10 +8,7 @@ Trigger.dev is an open source framework for creating long-running Jobs directly
You can use [Trigger.dev Cloud](https://cloud.trigger.dev) or [Self-host Trigger.dev](/documentation/guides/self-hosting) on your own infrastructure.
<Note>
Trigger.dev v2 currently only supports serverless. We will be adding [support for long-running
servers](https://github.com/triggerdotdev/trigger.dev/issues/244) soon.
</Note>
<Note>Trigger.dev v2 currently only supports serverless.</Note>
<CardGroup>
<Card title="Quick start guides" icon="person-running-fast" href="quickstarts/introduction">
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

+155
View File
@@ -49,6 +49,10 @@
{
"name": "Examples",
"url": "https://trigger.dev/apis"
},
{
"name": "v3 Developer Preview",
"url": "v3"
}
],
"redirects": [
@@ -427,6 +431,157 @@
{
"group": "Overview",
"pages": ["examples/introduction"]
},
{
"group": "",
"pages": ["v3/introduction"]
},
{
"group": "Getting Started",
"pages": [
"v3/quick-start",
"v3/upgrading-from-v2",
"v3/changelog",
"v3/feature-matrix",
"v3/limits"
]
},
{
"group": "Fundamentals",
"pages": [
"v3/trigger-folder",
"v3/tasks-overview",
"v3/triggering",
{
"group": "Task types",
"pages": ["v3/tasks-regular", "v3/tasks-scheduled", "v3/tasks-zod", "v3/tasks-webhooks"]
}
]
},
{
"group": "Development",
"pages": ["v3/cli-dev", "v3/run-tests"]
},
{
"group": "Deployment",
"pages": [
"v3/deploy-environment-variables",
"v3/cli-deploy",
"v3/github-actions",
{
"group": "Deployment integrations",
"pages": ["v3/vercel-integration"]
}
]
},
{
"group": "Writing tasks",
"pages": [
"v3/writing-tasks-introduction",
"v3/logging",
"v3/errors-retrying",
{
"group": "Wait",
"pages": [
"v3/wait",
"v3/wait-for",
"v3/wait-until",
"v3/wait-for-event",
"v3/wait-for-request"
]
},
"v3/queue-concurrency",
"v3/versioning",
"v3/machines",
"v3/idempotency",
"v3/reattempting-replaying",
"v3/trigger-filters",
"v3/notifications",
"v3/rollbacks",
"v3/using-apis",
"v3/middleware",
"v3/automated-tests"
]
},
{
"group": "Dashboard",
"pages": [
"v3/dashboard-overview",
"v3/dashboard-runs",
"v3/dashboard-tests",
"v3/dashboard-environment-variables"
]
},
{
"group": "API reference",
"pages": [
{
"group": "Functions",
"pages": [
"v3/reference-task",
"v3/reference-cron-task",
"v3/reference-cron-dynamic",
"v3/reference-interval-task",
"v3/reference-interval-dynamic",
"v3/reference-zod-task",
"v3/reference-zod-catalog",
"v3/reference-task-trigger",
"v3/reference-task-trigger-and-wait",
"v3/reference-task-batch-trigger",
"v3/reference-task-batch-trigger-and-wait",
"v3/reference-wait-for",
"v3/reference-wait-until",
"v3/reference-wait-for-event",
"v3/reference-wait-for-request",
"v3/reference-retry-on-throw",
"v3/reference-retry-fetch",
"v3/reference-retry-intercept-fetch",
"v3/reference-notification-catalog",
"v3/reference-notify",
"v3/reference-queue"
]
},
{
"group": "Objects",
"pages": ["v3/reference-context"]
},
{
"group": "CLI",
"pages": [
"v3/reference-cli-init",
"v3/reference-cli-dev",
"v3/reference-cli-deploy",
"v3/reference-cli-login",
"v3/reference-cli-logout",
"v3/reference-cli-update",
"v3/reference-cli-build",
"v3/reference-cli-who-am-i"
]
},
"v3/reference-trigger-config"
]
},
{
"group": "Architecture",
"pages": [
"v3/architecture-how-it-works",
"v3/architecture-multi-tenant-queue",
"v3/architecture-reliability"
]
},
{
"group": "Open source",
"pages": ["v3/github-repo", "v3/open-source-self-hosting", "v3/open-source-contributing"]
},
{
"group": "Help",
"pages": [
"v3/help-faqs",
"v3/community",
"v3/help-email",
"v3/help-slack",
"v3/help-uptime-status"
]
}
],
"footerSocials": {
+7
View File
@@ -0,0 +1,7 @@
---
title: "Architecture: How it works"
sidebarTitle: "How it works"
description: "An overview of how Trigger.dev v3 works under the hood."
---
<Snippet file="incomplete-docs.mdx" />
@@ -0,0 +1,7 @@
---
title: "Architecture: Multi-tenant queue"
sidebarTitle: "Multi-tenant queue"
description: "We built a reliable and fair multi-tenant queue that controls triggering all tasks."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "Architecture: Reliability"
sidebarTitle: "Reliability"
description: "How reliability is achieved with Trigger.dev."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Automated tests"
description: "Write automated tests of your tasks."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Changelog"
url: "https://trigger.dev/changelog"
---
Our [changelog](https://trigger.dev/changelog) is the best way to stay up to date with the latest changes to Trigger.
+88
View File
@@ -0,0 +1,88 @@
---
title: "CLI deploy command"
description: "The `trigger.dev deploy` command can be used to manually deploy."
---
You run the command like this:
<CodeGroup>
```bash npm
npx trigger.dev@v3 deploy
```
```bash pnpm
pnpm dlx trigger.dev@v3 deploy
```
```bash yarn
yarn dlx trigger.dev@v3 deploy
```
</CodeGroup>
It performs a few steps to deploy:
1. Typechecks the code.
2. Compiles and bundles the code.
3. Checks that [environment variables](/v3/deploy-environment-variables) are set.
4. Deploys the code to the cloud.
5. Registers the tasks as a new version in the environment (prod by default).
## Options
### Environment `--env` or `-e`
Defaults to `prod` but you can specify `staging`.
### Skip typecheck `--skip-typecheck` or `-T`
Skips the pre-build typecheck step.
### Build platform `--build-platform`
The platform to build the deployment image for. Defaults to `linux/amd64`.
### Log level `--log-level` or `-l`
The log level to use (debug, info, log, warn, error, none). Defaults to `log`.
### Set config filename `--config` or `-c`
The name of the config file, found where the command is run from. Defaults to `trigger.config.ts`.
### Set the projectRef `--project-ref` or `-p`
The project ref. Required if there is no config file.
### Self-hosted options
These options are usually only relevant to self-hosters or for local development.
#### Skip deploying the image `--skip-deploy` or `-D`
Load the built image into your local docker.
#### Self-hosted (builds locally) `--self-hosted`
Builds and loads the image using your local docker. Use the `--registry` option to specify the registry to push the image to when using `--self-hosted`, or just use `--push-image` to push to the default registry.
#### Registry `--registry`
<Snippet file="coming-soon-slim.mdx" />
The registry to push the image to when using --self-hosted.
#### Push image `--push-image`
<Snippet file="coming-soon-slim.mdx" />
When using the --self-hosted flag, push the image to the default registry. (defaults to false when not using --registry)
#### Tag the image `--tag`
<Snippet file="coming-soon-slim.mdx" />
Specify the tag to use when pushing the image to the registry.
{/* todo add options, remove the reference docs */}
+48
View File
@@ -0,0 +1,48 @@
---
title: "CLI dev command"
description: "The `trigger.dev dev` command is used to run your tasks locally."
---
This runs a server on your machine that can execute Trigger.dev tasks:
<CodeGroup>
```bash npm
npx trigger.dev@v3 dev
```
```bash pnpm
pnpm dlx trigger.dev@v3 dev
```
```bash yarn
yarn dlx trigger.dev@v3 dev
```
</CodeGroup>
You will see in the terminal that the server is running and listening for requests. When you run a task, you will see it in the terminal along with a link to view it in the dashboard.
It is worth noting that each task runs in a separate Node process. This means that if you have a long-running task, it will not block other tasks from running.
## Options
### Attaching a local debugger
You can use the `--debugger` flag to run the server in debug mode. This will allow you to attach a debugger to the server and debug your tasks.
<CodeGroup>
```bash npm
npx trigger.dev@v3 dev --debugger
```
```bash pnpm
pnpm dlx trigger.dev@v3 dev --debugger
```
```bash yarn
yarn dlx trigger.dev@v3 dev --debugger
```
</CodeGroup>
+6
View File
@@ -0,0 +1,6 @@
---
title: "Community"
url: "https://trigger.dev/discord"
---
Please [join our community on Discord](https://trigger.dev/discord) to ask questions, share your projects, and get help from other developers.
@@ -0,0 +1,7 @@
---
title: "Dashboard: environment variables"
sidebarTitle: "Environment Variables"
description: "Add, edit and delete Environment Variables from the Dashboard."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "Dashboard: overview"
sidebarTitle: "Overview"
description: "The dashboard has many features including: managing your projects, viewing run logs, editing environment variables and more."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "Dashboard: runs"
sidebarTitle: "Runs"
description: "Find runs and view the detailed traces and logs for each run."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "Dashboard: tests"
sidebarTitle: "Tests"
description: "Test your tasks in Dev, Staging and Prod from the dashboard."
---
<Snippet file="incomplete-docs.mdx" />
+65
View File
@@ -0,0 +1,65 @@
---
title: "Environment Variables"
description: "Any environment variables used in your tasks need to be added so the deployed code will run successfully."
---
An environment variable in Node.js is accessed in your code using `process.env.MY_ENV_VAR`.
We deploy your tasks and scale them up and down when they are triggered. So any environment variables you use in your tasks need to accessible to us so your code will run successfully.
## Setting environment variables
<Steps>
<Step title="Go to the Environment Variables page">
In the sidebar select the "Environment Variables" page, then press the "New environment variable"
button. ![Environment variables page](/images/v3/environment-variables-page.jpg)
</Step>
<Step title="Add your environment variables">
You can add values for your local dev environment, staging and prod. ![Environment variables
page](/images/v3/environment-variables-page.jpg){" "}
</Step>
</Steps>
<Note>
Specifying Dev values is optional. They will be overriden by values in your .env file when running
locally.
</Note>
## Editing environment variables
You can edit an environment variable's values. You cannot edit the key name, you must delete and create a new one.
<Steps>
<Step title="Press the action button on a variable">
![Environment variables page](/images/v3/environment-variables-actions.png)
</Step>
<Step title="Press edit">
![Environment variables page](/images/v3/environment-variables-edit-popover.png)
</Step>
</Steps>
## Deleting environment variables
<Warn>
Environment variables are fetched and injected before a runs begins. So if you delete one you can
cause runs to fail that are expecting variables to be set.
</Warn>
<Steps>
<Step title="Press the action button on a variable">
![Environment variables page](/images/v3/environment-variables-actions.png)
</Step>
<Step title="Press delete">
This will immediately delete the variable. ![Environment variables
page](/images/v3/environment-variables-delete-popover.png)
</Step>
</Steps>
+290
View File
@@ -0,0 +1,290 @@
---
title: "Errors & Retrying"
description: "How to deal with errors and write reliable tasks."
---
When an uncaught error is thrown inside your task, that task attempt will fail.
You can configure retrying in two ways:
1. In your [trigger.config file](/v3/reference-trigger-config) you can set the default retrying behavior for all tasks.
2. On each task you can set the retrying behavior.
<Note>
By default when you create your project using the CLI init command we disabled retrying in the DEV
environment. You can enable it in your [trigger.config file](/v3/reference-trigger-config).
</Note>
## A simple example with OpenAI
This task will retry 10 times with exponential backoff.
- `openai.chat.completions.create()` can throw an error.
- The result can be empty and we want to try again. So we manually throw an error.
<Snippet file="v3/code/openai-retry.mdx" />
## Combining tasks
One way to gain reliability is to break your work into smaller tasks and [trigger](/v3/triggering) them from each other. Each task can have its own retrying behavior:
```ts /trigger/multiple-tasks.ts
export const myTask = task({
id: "my-task",
retry: {
maxAttempts: 10,
},
run: async (payload: string) => {
const result = await otherTask.triggerAndWait({ payload: "some data" });
//...do other stuff
},
});
export const otherTask = task({
id: "other-task",
retry: {
maxAttempts: 5,
},
run: async (payload: string) => {
return {
foo: "bar",
};
},
});
```
Another benefit of this approach is that you can view the logs and retry each task independently from the dashboard.
## Retrying smaller parts of a task
Another complimentary strategy is to perform retrying inside of your task.
We provide some useful functions that you can use to retry smaller parts of a task. Of course, you can also write your own logic or use other packages.
### retry.onThrow()
You can retry a block of code that can throw an error, with the same retry settings as a task.
```ts /trigger/retry-on-throw.ts
export const retryOnThrow = task({
id: "retry-on-throw",
run: async (payload: any) => {
//Will retry up to 3 times. If it fails 3 times it will throw.
const result = await retry.onThrow(
async ({ attempt }) => {
//throw on purpose the first 2 times, obviously this is a contrived example
if (attempt < 3) throw new Error("failed");
//...
return {
foo: "bar",
};
},
{ maxAttempts: 3, randomize: false }
);
//this will log out after 3 attempts of retry.onThrow
logger.info("Result", { result });
},
});
```
<Note>
If all of the attempts with `retry.onThrow` fail, an error will be thrown. You can catch this or
let it cause a retry of the entire task.
</Note>
### retry.fetch()
You can use `fetch`, `axios`, or any other library in your code.
But we do provide a convenient function to perform HTTP requests with conditional retrying based on the response:
```ts /trigger/retry-fetch.ts
export const taskWithFetchRetries = task({
id: "task-with-fetch-retries",
run: async ({ payload, ctx }) => {
//if the Response is a 429 (too many requests), it will retry using the data from the response. A lot of good APIs send these headers.
const headersResponse = await retry.fetch("http://my.host/test-headers", {
retry: {
"429": {
strategy: "headers",
limitHeader: "x-ratelimit-limit",
remainingHeader: "x-ratelimit-remaining",
resetHeader: "x-ratelimit-reset",
resetFormat: "unix_timestamp_in_ms",
},
},
});
const json = await headersResponse.json();
logger.info("Fetched headers response", { json });
//if the Response is a 500-599 (issue with the server you're calling), it will retry up to 10 times with exponential backoff
const backoffResponse = await retry.fetch("http://my.host/test-backoff", {
retry: {
"500-599": {
strategy: "backoff",
maxAttempts: 10,
factor: 2,
minTimeoutInMs: 1_000,
maxTimeoutInMs: 30_000,
randomize: false,
},
},
});
const json2 = await backoffResponse.json();
logger.info("Fetched backoff response", { json2 });
//You can additionally specify a timeout. In this case if the response takes longer than 1 second, it will retry up to 5 times with exponential backoff
const timeoutResponse = await retry.fetch("https://httpbin.org/delay/2", {
timeout: {
durationInMs: 1000,
retry: {
maxAttempts: 5,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
randomize: false,
},
},
});
const json3 = await timeoutResponse.json();
logger.info("Fetched timeout response", { json3 });
return {
result: "success",
payload,
json,
json2,
json3,
};
},
});
```
<Note>
If all of the attempts with `retry.fetch` fail, an error will be thrown. You can catch this or let
it cause a retry of the entire task.
</Note>
## Advanced error handling and retrying
We provide a `handleError` callback on the task and in your `trigger.config` file. This gets called when an uncaught error is thrown in your task.
You can
- Inspect the error, log it, and return a different error if you'd like.
- Modify the retrying behavior based on the error, payload, context, etc.
If you don't return anything from the function it will use the settings on the task (or inherited from the config). So you only need to use this to override things.
### OpenAI error handling example
OpenAI calls can fail for a lot of reasons and the ideal retry behavior is different for each.
In this complicated example:
- We skip retrying if there's no Response status.
- We skip retrying if you've run out of credits.
- If there are no Response headers we let the normal retrying logic handle it (return undefined).
- If we've run out of requests or tokens we retry at the time specified in the headers.
```ts
export const openaiTask = task({
id: "openai-task",
retry: {
maxAttempts: 1,
},
run: async (payload: { prompt: string }) => {
const chatCompletion = await openai.chat.completions.create({
messages: [{ role: "user", content: payload.prompt }],
model: "gpt-3.5-turbo",
});
return chatCompletion.choices[0].message.content;
},
handleError: async (payload, error, { ctx, retryAt }) => {
if (error instanceof OpenAI.APIError) {
if (!error.status) {
return {
skipRetrying: true,
};
}
if (error.status === 429 && error.type === "insufficient_quota") {
return {
skipRetrying: true,
};
}
if (!error.headers) {
//returning undefined means the normal retrying logic will be used
return;
}
const remainingRequests = error.headers["x-ratelimit-remaining-requests"];
const requestResets = error.headers["x-ratelimit-reset-requests"];
if (typeof remainingRequests === "string" && Number(remainingRequests) === 0) {
return {
retryAt: calculateISO8601DurationOpenAIVariantResetAt(requestResets),
};
}
const remainingTokens = error.headers["x-ratelimit-remaining-tokens"];
const tokensResets = error.headers["x-ratelimit-reset-tokens"];
if (typeof remainingTokens === "string" && Number(remainingTokens) === 0) {
return {
retryAt: calculateISO8601DurationOpenAIVariantResetAt(tokensResets),
};
}
}
},
});
```
## Using try/catch to prevent retries
Sometimes you want to catch an error and don't want to retry the task. You can use try/catch as you normally would. In this example we fallback to using Replicate if OpenAI fails.
```ts /trigger/
import { task } from "@trigger.dev/sdk/v3";
export const openaiTask = task({
id: "openai-task",
run: async (payload: { prompt: string }) => {
try {
//if this fails, it will throw an error and retry
const chatCompletion = await openai.chat.completions.create({
messages: [{ role: "user", content: payload.prompt }],
model: "gpt-3.5-turbo",
});
if (chatCompletion.choices[0]?.message.content === undefined) {
//sometimes OpenAI returns an empty response, let's retry by throwing an error
throw new Error("OpenAI call failed");
}
return chatCompletion.choices[0].message.content;
} catch (error) {
//use Replicate if OpenAI fails
const prediction = await replicate.run(
"meta/llama-2-70b-chat:02e509c789964a7ea8736978a43525956ef40397be9033abf9fd2badfe68c9e3",
{
input: {
prompt: payload.prompt,
max_new_tokens: 250,
},
}
);
if (prediction.output === undefined) {
//retry if Replicate fails
throw new Error("Replicate call failed");
}
return prediction.output;
}
},
});
```
+10
View File
@@ -0,0 +1,10 @@
---
title: "Feature matrix"
description: "What features are currently available in the Developer Preview"
---
| Feature | Description | Status |
| -------------------------------------- | ------------------------------------------ | ------ |
| [Regular tasks](/v3/tasks-regular) | A task that can be triggered from anywhere | ✅ |
| [Scheduled tasks](/v3/tasks-scheduled) | A task that can be triggered on a schedule | ⏳ |
| [Webhook tasks](v3/tasks-webhooks) | A task that can be triggered by a webhook | ⏳ |
+41
View File
@@ -0,0 +1,41 @@
---
title: "GitHub Actions"
description: "You can easily deploy your tasks with GitHub actions."
---
This simple GitHub action file will deploy you Trigger.dev tasks when new code is pushed to the `main` branch and the `trigger` directory has changes in it.
```yaml .github/workflows/release-trigger.yml
name: Deploy to Trigger.dev
on:
push:
branches:
- main
paths:
- "trigger/**"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: 🚀 Deploy Trigger.dev
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
run: |
npx trigger.dev@v3 deploy
```
If you already have a GitHub action file, you can just add the final step "🚀 Deploy Trigger.dev" to your existing file.
You need to add the `TRIGGER_ACCESS_TOKEN` secret to your repository. You can create a new access token by going to your profile page and then clicking on the "Personal Access Tokens" tab.
To set it in GitHub go to your repository, click on "Settings", "Secrets and variables" and then "Actions". Add a new secret with the name `TRIGGER_ACCESS_TOKEN` and use the value of your access token.
+8
View File
@@ -0,0 +1,8 @@
---
title: "GitHub repo"
url: "https://github.com/triggerdotdev/trigger.dev"
---
Trigger.dev is [Open Source on GitHub](https://github.com/triggerdotdev/trigger.dev). You can contribute to the project by submitting issues, pull requests, or simply by using it and providing feedback.
You can also [self-host](/v3/open-source-self-hosting) the project if you want to run it on your own infrastructure.
+6
View File
@@ -0,0 +1,6 @@
---
title: "Email us"
url: "https://trigger.dev/contact"
---
You can [email us](https://trigger.dev/contact) by filling out this form.
+6
View File
@@ -0,0 +1,6 @@
---
title: "Frequently Asked Questions"
sidebarTitle: "FAQs"
---
<Snippet file="incomplete-docs.mdx" />
+11
View File
@@ -0,0 +1,11 @@
---
title: "Slack"
---
If you have a paid Trigger.dev account, you can request a private Slack Connect channel.
To do this:
1. Login to the [Trigger.dev web app](https://cloud.trigger.dev).
2. Subscribe to a paid plan if you haven't already.
3. In the bottom-left corner click "Join our Slack".
+6
View File
@@ -0,0 +1,6 @@
---
title: "Uptime status"
url: "https://trigger.openstatus.dev/"
---
View the [current Trigger.dev Cloud system status](https://trigger.openstatus.dev/).
+6
View File
@@ -0,0 +1,6 @@
---
title: "Idempotency"
description: "An API call or operation is “idempotent” if it has the same result when called more than once."
---
<Snippet file="incomplete-docs.mdx" />
+77
View File
@@ -0,0 +1,77 @@
---
title: "Introduction"
description: "Welcome to the Trigger.dev v3 documentation."
---
<Warning>
The Trigger.dev v3 Developer Preview is currently in invite-only early access. [Sign up here to
request access](https://trigger.dev/v3-early-access).
</Warning>
## What is Trigger.dev (v3)?
Trigger.dev v3 makes it easy to write reliable long-running tasks without timeouts.
- We run your tasks with no timeouts. You don't have to manage any infrastructure (unless you [self-host](/v3/open-source-self-hosting)). Workers are automatically scaled and managed for you.
- We provide a multi-tenant queue that is used when triggering tasks.
- We provide an SDK and CLI for writing tasks in your existing codebase, inside [/trigger folders](/v3/trigger-folder).
- We provide different types of tasks: [regular](/v3/tasks-regular), [scheduled](/v3/tasks-scheduled), [zod](/v3/tasks-zod), [webhooks](/v3/tasks-webhooks).
- We provide a dashboard for monitoring, debugging, and managing your tasks.
We're [open source](https://github.com/triggerdotdev/trigger.dev) and you can choose to use the [Trigger.dev Cloud](https://cloud.trigger.dev) or [Self-host Trigger.dev](/v3/open-source-self-hosting) on your own infrastructure.
## Getting started
<CardGroup>
<Card title="Quick start guide" icon="person-running-fast" href="/v3/quick-start">
Get started in 3 minutes.
</Card>
<Card title="Writing tasks" icon="wand-magic-sparkles" href="/v3/tasks-overview">
Tasks are the core of Trigger.dev. Learn what they are and how to write them.
</Card>
</CardGroup>
## Getting help
We'd love to hear from you or give you a hand getting started. Here are some ways to get in touch with us. We'd also ❤️ your support.
<CardGroup>
<Card
title="Join our Discord server"
icon="discord"
href="https://discord.gg/kA47vcd8P6"
color="#5865F2"
>
The help forum is a great place to get help with any questions about Trigger.dev.
</Card>
<Card
title="Follow us on X (Twitter)"
icon={
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 0 512 512">
<path d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z" />
</svg>
}
href="https://twitter.com/triggerdotdev"
color="#1DA1F2"
>
Follow us on X (Twitter) to get the latest updates and news.
</Card>
<Card
title="Schedule a call"
icon="phone"
iconType="solid"
href="https://cal.com/team/triggerdotdev/founders-call"
>
Arrange a call with one of the founders. We can help answer questions and give 1-on-1 help
building your first task.
</Card>
<Card
title="Give us a star on GitHub"
icon="star"
iconType="solid"
href="https://github.com/triggerdotdev/trigger.dev"
color="#fbbf24"
>
Check us out at triggerdotdev/trigger.dev
</Card>
</CardGroup>
+5
View File
@@ -0,0 +1,5 @@
---
title: "Limits"
---
<Snippet file="incomplete-docs.mdx" />
+79
View File
@@ -0,0 +1,79 @@
---
title: "Logging and tracing"
description: "How to use the built-in logging and tracing system."
---
![The run log
](/images/v3/run-log.png)
The [run log](/v3/dashboard-runs) shows you exactly what happened in every run of your tasks. It is comprised of logs, traces and spans.
## Logs
You can use `console.log()`, `console.error()`, etc as normal and they will be shown in your run log. This is the standard function so you can use it as you would in any other JavaScript or TypeScript code. Logs from any functions/packages will also be shown.
### logger
We recommend that you use our `logger` object which creates structured logs. Structured logs will make it easier for you to search the logs to quickly find runs.
```ts /trigger/logging.ts
import { task, logger } from "@trigger.dev/sdk/v3";
export const loggingExample = task({
id: "logging-example",
run: async (payload: { data: Record<string, string> }) => {
//the first parameter is the message, the second parameter must be a key-value object (Record<string, unknown>)
logger.debug("Debug message", payload.data);
logger.log("Log message", payload.data);
logger.info("Info message", payload.data);
logger.warn("You've been warned", payload.data);
logger.error("Error message", payload.data);
},
});
```
## Tracing and spans
Tracing is a way to follow the flow of your code. It's very useful for debugging and understanding how your code is working, especially with long-running or complex tasks.
Trigger.dev uses OpenTelemetry tracing under the hood. With automatic tracing for many things like task triggering, task attempts, HTTP requests, and more.
### Automatic instrumentation
| Name | Description |
| ------------- | -------------------------------- |
| Task triggers | Task triggers. |
| Task attempts | Task attempts. |
| HTTP requests | HTTP requests made by your code. |
| OpenAI | OpenAI SDK calls. |
We want to provide automatic instrumentation for as many things as possible. Please do [request any automatic instrumentation](https://github.com/triggerdotdev/trigger.dev/issues/new?template=instrumentation_request.yml) you would like to see.
## Add custom traces
If you want to add custom traces to your code, you can use the `logger.trace` function. It will create a new OTEL trace and you can set attributes on it.
```ts
import { logger, task } from "@trigger.dev/sdk/v3";
export const customTrace = task({
id: "custom-trace",
run: async (payload) => {
//you can wrap code in a trace, and set attributes
const user = await logger.trace("fetch-user", async (span) => {
span.setAttribute("user.id", "1");
//...do stuff
//you can return a value
return {
id: "1",
name: "John Doe",
fetchedAt: new Date(),
};
});
const usersName = user.name;
},
});
```
+23
View File
@@ -0,0 +1,23 @@
---
title: "Machines"
description: "Configure the number of vCPUs and GBs of RAM you want the task to use."
---
The `machine` configuration is optional. Using higher spec machines will increase the cost of running the task but can also improve the performance of the task if it is CPU or memory bound.
```ts /trigger/heavy-task.ts
export const heavyTask = task({
id: "heavy-task",
machine: {
cpu: 2,
memory: 4,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
## Possible configurations
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Middleware"
description: "This function is called before the `run` function, it allows you to wrap the run function with custom code."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Notifications"
description: "Send and receive notifications from your tasks to make your other systems aware of changes. For example, you can live-update your website as a task progresses."
---
<Snippet file="coming-soon.mdx" />
+16
View File
@@ -0,0 +1,16 @@
---
title: "Contributing"
description: "You can contribute to Trigger.dev in many ways."
---
Go to our [GitHub repository](https://github.com/triggerdotdev/trigger.dev) and open an issue or a pull request. We are always looking for contributors to help us improve Trigger.dev. You can contribute in many ways, including:
- Reporting bugs
- Suggesting new features
- Writing documentation
- Writing code
- Reviewing code
- Translating the app
- Sharing the app with others
- Giving feedback
- And more!
+6
View File
@@ -0,0 +1,6 @@
---
title: "Self-hosting"
description: "You can self-host Trigger.dev on your own infrastructure."
---
<Snippet file="incomplete-docs.mdx" />
+181
View File
@@ -0,0 +1,181 @@
---
title: "Concurrency & Queues"
description: "Configure what you want to happen when there is more than one run at a time."
---
Controlling concurrency is useful when you have a task that can't be run concurrently, or when you want to limit the number of runs to avoid overloading a resource.
## One at a time
This task will only ever have a single run executing at a time. All other runs will be queued until the current run is complete.
```ts /trigger/one-at-a-time.ts
export const oneAtATime = task({
id: "one-at-a-time",
queue: {
concurrencyLimit: 1,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
## Parallelism
You can execute lots of tasks at once by combining high concurrency with [batch triggering](/v3/triggering) (or just triggering in a loop).
```ts /trigger/parallelism.ts
export const parallelism = task({
id: "parallelism",
queue: {
concurrencyLimit: 100,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
<Warning>
Be careful with high concurrency. If you're doing API requests you might hit rate limits. If
you're hitting your database you might overload it.
</Warning>
<Note>
Your organization has a maximum concurrency limit which depends on your plan. If you're a paying
customer you can request a higher limit by [contacting us](https://www.trigger.dev/contact).
</Note>
## Defining a queue
As well as putting queue settings directly on a task, you can define a queue and reuse it across multiple tasks. This allows you to share the same concurrency limit:
```ts /trigger/queue.ts
const myQueue = queue({
name: "my-queue",
concurrencyLimit: 1,
});
export const task1 = task({
id: "task-1",
queue: {
name: "my-queue",
},
run: async (payload: { message: string }) => {
// ...
},
});
export const task2 = task({
id: "task-2",
queue: {
name: "my-queue",
},
run: async (payload: { message: string }) => {
// ...
},
});
```
## Setting the concurrency when you trigger a run
When you trigger a task you can override the concurrency limit. This is really useful if you sometimes have high priority runs.
The task:
```ts /trigger/override-concurrency.ts
const generatePullRequest = task({
id: "generate-pull-request",
queue: {
//normally when triggering this task it will be limited to 1 run at a time
concurrencyLimit: 1,
},
run: async (payload) => {
//todo generate a PR using OpenAI
},
});
```
Triggering from your backend and overriding the concurrency:
```ts app/api/push/route.ts
import { generatePullRequest } from "~/trigger/override-concurrency";
export async function POST(request: Request) {
const data = await request.json();
if (data.branch === "main") {
//trigger the task, with a different queue
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//the "main-branch" queue will have a concurrency limit of 10
//this triggered run will use that queue
name: "main-branch",
concurrencyLimit: 10,
},
},
});
return Response.json(handle);
} else {
//triggered with the default (concurrency of 1)
const handle = await generatePullRequest.trigger({
payload: data,
});
return Response.json(handle);
}
}
```
## Concurrency keys and per-tenant queuing
If you're building an application where you want to run tasks for your users, you might want a separate queue for each of your users. (It doesn't have to be users, it can be any entity you want to separately limit the concurrency for.)
You can do this by using `concurrencyKey`. It creates a separate queue for each value of the key.
Your backend code:
```ts app/api/pr/route.ts
import { generatePullRequest } from "~/trigger/override-concurrency";
export async function POST(request: Request) {
const data = await request.json();
if (data.isFreeUser) {
//free users can only have 1 PR generated at a time
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//every free user gets a queue with a concurrency limit of 1
name: "free-users",
concurrencyLimit: 1,
concurrencyKey: data.userId,
},
},
});
//return a success response with the handle
return Response.json(handle);
} else {
//trigger the task, with a different queue
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//every paid user gets a queue with a concurrency limit of 10
name: "paid-users",
concurrencyLimit: 10,
concurrencyKey: data.userId,
},
},
});
//return a success response with the handle
return Response.json(handle);
}
}
```
+119
View File
@@ -0,0 +1,119 @@
---
title: "Quick start"
description: "How to get started in 3 minutes using the CLI and SDK."
---
In this guide we will:
1. Create a `trigger.config.ts` file and a `/trigger` directory with an example task.
2. Get you to run the task using the CLI.
3. Show you how to view the run logs for that task.
<Steps titleSize="h3">
<Step title="Create a Trigger.dev account">
You can either:
- Use the [Trigger.dev Cloud](https://cloud.trigger.dev).
- Or [self-host](/v3/open-source-self-hosting) the service.
</Step>
<Step title="Create your first project">
Once you've created an account, follow the steps in the app to:
1. Complete your account details.
2. Create your first Organization and Project.
<Warning>
Make sure you create a "Version 3" project. You might need to [request early
access](https://trigger.dev/v3-early-access).
</Warning>
</Step>
<Step title="Run the CLI `init` command">
The easiest way to get started it to use the CLI. It will add Trigger.dev to your existing project, create a `/trigger` folder and give you an example task.
Run this command in the root of your project to get started:
<CodeGroup>
```bash npm
npx trigger.dev@v3 init
```
```bash pnpm
pnpm dlx trigger.dev@v3 init
```
```bash yarn
yarn dlx trigger.dev@v3 init
```
</CodeGroup>
It will do a few things:
1. Log you into the CLI if you're not already logged in.
2. Create a `trigger.config.ts` file in the root of your project.
3. Ask where you'd like to create the `/trigger` directory.
4. Create the `/trigger` directory with an example task, `/trigger/example.[ts/js]`.
</Step>
<Step title="Run the CLI `dev` command">
The CLI `dev` command runs a server for your tasks. It will watches for changes in your `/trigger` directory and communicates with the Trigger.dev platform to register your tasks, perform runs, and send data back and forth.
<CodeGroup>
```bash npm
npx trigger.dev@v3 dev
```
```bash pnpm
pnpm dlx trigger.dev@v3 dev
```
```bash yarn
yarn dlx trigger.dev@v3 dev
```
</CodeGroup>
</Step>
<Step title="Perform a run test using the dashboard">
The CLI `dev` command spits out various useful URLs. Right now we want to visit the Test page it provided.
You should see our Example task in the list, select it. Most tasks have a "payload" which you enter in the JSON editor, but our example task doesn't need any input.
Press the "Run test" button.
</Step>
<Step title="View your run">
Congratulations, you should see the run page which will live reload showing you the current state of the run.
If you go back to your terminal you'll see that the dev command also shows tasks that are running and links to the run log.
</Step>
</Steps>
## Next steps
<CardGroup>
<Card title="How to trigger your tasks" icon="bolt" href="/v3/triggering">
Learn how to trigger tasks from your code.
</Card>
<Card title="Writing tasks" icon="wand-magic-sparkles" href="/v3/tasks-overview">
Tasks are the core of Trigger.dev. Learn what they are and how to write them.
</Card>
</CardGroup>
+6
View File
@@ -0,0 +1,6 @@
---
title: "Reattempting & Replaying"
description: "You can reattempt a task that has failed all of its attempts. You can also replay a task with a new version of your code."
---
<Snippet file="coming-soon.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev build"
sidebarTitle: "build"
description: "This command will build your tasks."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev deploy"
sidebarTitle: "deploy"
description: "This command will deploy your tasks."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev dev"
sidebarTitle: "dev"
description: "This command runs your tasks locally."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev init"
sidebarTitle: "init"
description: "This command will setup your v3 project."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev login"
sidebarTitle: "login"
description: "This command will log you in to the CLI. Required to run any other command."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev logout"
sidebarTitle: "logout"
description: "This command will log you out of the CLI."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev update"
sidebarTitle: "update"
description: "This command can be used to update all of your trigger.dev packages to the latest versions."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "trigger.dev whoami"
sidebarTitle: "whoami"
description: "This command will return information about you, the logged in user."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Context"
description: "The Context object is part of the `run` function parameter and provides information about the current run."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "cron.dynamic()"
description: "Trigger a task with many different CRON schedules. For example you can use this to let your users select when they want a reminder."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "cron.task()"
description: "Trigger a task on a recurring schedule using a CRON expression."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "interval.dynamic()"
description: "Trigger a task with many different interval schedules. For example you can use this to let your users select how often they want a reminder."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "interval.task()"
description: "Trigger a task on a recurring schedule using the time interval you want between runs."
---
<Snippet file="coming-soon.mdx" />
@@ -0,0 +1,6 @@
---
title: "notification.catalog()"
description: "Create a set of events that can be emitted from your tasks. These can be subscribed to from your application to provide real-time updates to your users."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "notify()"
description: "Send a notification from your tasks. These can be subscribed to from your application to provide real-time updates to your users."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "queue()"
description: "Create queue settings that can be used when triggering a task."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "retry.fetch()"
description: "Inside a task, do a fetch request that will retry (you can specify the retry conditions)."
---
<Snippet file="incomplete-docs.mdx" />
@@ -0,0 +1,6 @@
---
title: "retry.interceptFetch()"
description: "Useful when writing automated tests it will intercept matching HTTP requests and respond with what you provide."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "retry.onThrow()"
description: "Inside a task, retry the wrapped code if it throws an error."
---
<Snippet file="incomplete-docs.mdx" />
@@ -0,0 +1,6 @@
---
title: "task.batchTriggerAndWait()"
description: "Trigger a task many times at once from inside another task, and wait for all the results."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "task.batchTrigger()"
description: "Trigger a task many times at once from your code."
---
<Snippet file="incomplete-docs.mdx" />
@@ -0,0 +1,6 @@
---
title: "task.triggerAndWait()"
description: "Trigger a task from inside another task, and wait for the result."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "task.trigger()"
description: "Trigger a task from your code."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "task()"
description: "The task() function is the simplest way to create a long-running task."
---
<Snippet file="incomplete-docs.mdx" />
+7
View File
@@ -0,0 +1,7 @@
---
title: "The trigger.config.js file"
sidebarTitle: "trigger.config file"
description: "This file is used to configure some settings for your project."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "wait.forEvent()"
description: "Inside a task, wait until a specific event is received before continuing."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "wait.forRequest()"
description: "Inside a task, wait until a specific request is received before continuing."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "wait.for()"
description: "Inside a task, wait for a period of time before continuing."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "wait.until()"
description: "Inside a task, wait until the specified date before continuing."
---
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "zod.catalog()"
description: "Create a set of events with names and payloads that are parsed using Zod schemas."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "zod.task()"
description: "A task where the payload is parsed using a zod schema."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Rollbacks"
description: "You can rollback changes when errors happen, to give transactional guarantees to your operations."
---
<Snippet file="coming-soon.mdx" />
+26
View File
@@ -0,0 +1,26 @@
---
title: "Run tests"
description: "You can use the dashboard to run a test of your tasks."
---
From the "Test" page in the sidebar of the dashboard you can run a test for any of your tasks, that includes for any environment.
<Steps>
<Step title="Select an environment">
![Select an environment](/images/v3/test-select-environment.png)
</Step>
<Step title="Select the task to test">
![Select the task to test](/images/v3/test-select-task.png)
</Step>
<Step title="Enter a payload">
Select a recent payload as a starting point or enter from scratch. Payloads must be valid JSON you will see helpful errors if it is not. Press the "Run test" button or use the keyboard shortcut to run the test.
![Enter a payload](/images/v3/test-set-payload.png)
</Step>
<Step title="View the run live">![View the run live](/images/v3/run-in-progress.png)</Step>
</Steps>
+155
View File
@@ -0,0 +1,155 @@
---
title: "Tasks: Overview"
sidebarTitle: "Tasks"
description: "Tasks are functions that can run for a long time and provide strong resilience to failure."
---
There are different types of tasks including [regular tasks](/v3/tasks-regular), [scheduled tasks](/v3/tasks-scheduled), [zod tasks](/v3/tasks-zod) and [webhook tasks](/v3/tasks-webhooks).
## Hello world task and how to trigger it
Here's an incredibly simple task:
```ts /trigger/hello-world.ts
import { task } from "@trigger.dev/sdk/v3";
//1. You need to export each task
export const helloWorld = task({
//2. Use a unique id for each task
id: "hello-world",
//3. The run function is the main function of the task
run: async (payload: { message: string }) => {
//4. You can write code that runs for a long time here, there are no timeouts
console.log(payload.message);
},
});
```
You can trigger this in two ways:
1. From the dashboard [using the "Test" feature](/v3/develop-run-tests).
2. Trigger it from your backend code. See the [full triggering guide here](/v3/triggering).
Here's how to trigger a single run from elsewhere in your code:
```ts Your backend code
import { helloWorldTask } from "./trigger/hello-world";
async function triggerHelloWorld() {
//This triggers the task and return a handle
const handle = await helloWorld.trigger({ payload: { message: "Hello world!" } });
//You can use the handle to check the status of the task, cancel and retry it.
console.log("Task is running with handle", handle.id);
}
```
You can also [trigger a task from another task](/v3/triggering), and wait for the result.
## Defining a `task`
The task function takes an object with the following fields.
### The `id` field
This is used to identify your task so it can be triggered, managed, and you can view runs in the dashboard. This must be unique in your project we recommend making it descriptive and unique.
### The `run` function
Your custom code inside `run()` will be executed when your task is triggered. Its an async function that has two arguments:
1. The run payload - the data that you pass to the task when you trigger it.
2. An object with `ctx` about the run ([Context](/v3/reference-context)), and any output from the optional `init` function that runs before every run attempt.
Anything you return from the `run` function will be the result of the task. Data you return must be JSON serializable: strings, numbers, booleans, arrays, objects, and null.
### `retry` options
A task is retried if an error is thrown, by default we retry 3 times.
You can set the number of retries and the delay between retries in the `retry` field:
```ts /trigger/retry.ts
export const taskWithRetries = task({
id: "task-with-retries",
retry: {
maxAttempts: 10,
factor: 1.8,
minTimeoutInMs: 500,
maxTimeoutInMs: 30_000,
randomize: false,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
For more information read [the retrying guide](/v3/retrying), or see the [SDK reference](/v3/reference-task).
It's also worth mentioning that you can [retry a block of code](/v3/retrying) inside your tasks as well.
### `queue` options
Queues allow you to control the concurrency of your tasks. This allows you to have one-at-a-time execution and parallel executions. There are also more advanced techniques like having different concurrencies for different sets of your users. For more information read [the concurrency & queues guide](/v3/queue-concurrency).
```ts /trigger/one-at-a-time.ts
export const oneAtATime = task({
id: "one-at-a-time",
queue: {
concurrencyLimit: 1,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
### `machine` options
Some tasks require more vCPUs or GBs of RAM. You can specify these requirements in the `machine` field. For more information read [the machines guide](/v3/machines).
```ts /trigger/heavy-task.ts
export const heavyTask = task({
id: "heavy-task",
machine: {
cpu: 2,
memory: 4,
},
run: async ({ payload, ctx }) => {
//...
},
});
```
### `init` function
This function is called before a run attempt.
### `cleanup` function
This function is called after a run attempt has succeeded or failed.
### `middleware` function
This function is called before the `run` function, it allows you to wrap the run function with custom code. For more information [read the guide](/v3/middleware).
### `onSuccess` function
When a task attempt succeeds, the `onSuccess` function is called. It's useful for sending notifications, logging, or other side effects.
<Snippet file="coming-soon-slim.mdx" />
### `onError` function
When a task attempt fails, the `onError` function is called. It's useful for sending notifications, logging, or other side effects.
<Snippet file="coming-soon-slim.mdx" />
## Next steps
<CardGroup>
<Card title="Writing tasks" icon="wand-magic-sparkles" href="/v3/writing-tasks-introduction">
Tasks are the core of Trigger.dev. Learn how to write them.
</Card>
</CardGroup>
+86
View File
@@ -0,0 +1,86 @@
---
title: "Regular tasks"
description: "The simplest type of task which can be triggered from elsewhere in your code."
---
They are defined using the `task()` function and can be [triggered](/v3/triggering) from your backend or inside another task.
Like all tasks they don't have timeouts, they should be placed inside a [/trigger folder](/v3/trigger-folder), and you [can configure them](/v3/tasks-overview#defining-a-task).
## Example tasks
### A task that does an OpenAI call with retrying
Sometimes OpenAI calls can take a long time to complete, or they can fail. This task will retry if the API call fails completely or if the response is empty.
<Snippet file="v3/code/openai-retry.mdx" />
### A Task that sends emails in a sequence with delays in between
This example uses Resend to send a sequence of emails over several days.
Each email is wrapped in [retry.onThrow](/v3/reference-retry-on-throw). This will retry the block of code if an error is thrown. This is useful when you don't want to retry the whole task, but just a part of it. The entire task will use the default retrying, so can also retry.
Additionally this task uses `wait.for` to wait for a certain amount of time before sending the next email. During the waiting time, the task will be paused and will not consume any resources.
```ts /trigger/email-sequence.ts
import { Resend } from "resend";
const resend = new Resend(process.env.RESEND_ASP_KEY);
export const emailSequence = task({
id: "email-sequence",
run: async (payload: { userId: string; email: string; name: string }) => {
console.log(`Start email sequence for user ${payload.userId}`, payload);
//send the first email immediately
const firstEmailResult = await retry.onThrow(
async ({ attempt }) => {
const { data, error } = await resend.emails.send({
from: "hello@trigger.dev",
to: payload.email,
subject: "Welcome to Trigger.dev",
html: `<p>Hello ${payload.name},</p><p>Welcome to Trigger.dev</p>`,
});
if (error) {
//throwing an error will trigger a retry of this block
throw error;
}
return data;
},
{ maxAttempts: 3 }
);
//then wait 3 days
await wait.for({ days: 3 });
//send the second email
const secondEmailResult = await retry.onThrow(
async ({ attempt }) => {
const { data, error } = await resend.emails.send({
from: "hello@trigger.dev",
to: payload.email,
subject: "Some tips for you",
html: `<p>Hello ${payload.name},</p><p>Here are some tips for you…</p>`,
});
if (error) {
//throwing an error will trigger a retry of this block
throw error;
}
return data;
},
{ maxAttempts: 3 }
);
//etc...
},
});
```
### Other examples
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Scheduled tasks"
description: "A task that is triggered on a recurring schedule using CRON syntax or an interval."
---
<Snippet file="coming-soon.mdx" />
+12
View File
@@ -0,0 +1,12 @@
---
title: "Webhook tasks"
description: "A task that is triggered when a webhook is received from an API."
---
## Built-in webhooks triggers
<Snippet file="coming-soon.mdx" />
## How to manually use Trigger.dev with webhooks
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Zod tasks"
description: "You can use Zod to define a catalog of events and then attach those events to your tasks."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Trigger filters"
description: "You can add filters to your tasks so they're only triggered when certain conditions are met."
---
<Snippet file="coming-soon.mdx" />
+25
View File
@@ -0,0 +1,25 @@
---
title: "/trigger folders"
description: "Your tasks live inside /trigger folders. Code in these is bundled and deployed together."
---
## What gets bundled?
We automatically bundle everything for your tasks. This includes:
- Your tasks (they can be in any file inside a /trigger folder, they just need to be exported with a name).
- Imported npm packages.
- Other imports from your code.
This means you shouldn't need to think about what gets bundled. Just write your tasks and we'll take care of the rest.
## Multiple `/trigger` folders
You can have multiple `/trigger` folders in your repository.
- Each `/trigger` folder can have many tasks exported from it.
- Each file inside a `/trigger` folder can export many tasks.
### (Optional) configuration
It is possible to manually set one or more folders as `/trigger` folders in your `trigger.config` file. View the [trigger.config documentation](/v3/referece-trigger-config) for more information.
+186
View File
@@ -0,0 +1,186 @@
---
title: "Triggering"
description: "Tasks need to be triggered to run."
---
There are currently four ways you can trigger any task from your own code:
| Function | Where does this work? | What it does |
| -------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `yourTask.trigger()` | Anywhere | Triggers a task and gets a handle you can use to monitor and manage the run. It does not wait for the result. |
| `yourTask.batchTriggerAndWait()` | Anywhere | Triggers a task multiple times and gets a handle you can use to monitor and manage the runs. It does not wait for the results. |
| `yourTask.triggerAndWait()` | Inside a task | Triggers a task and then waits until it's complete. You get the result data to continue with. |
| `yourTask.batchTriggerAndWait()` | Inside a task | Triggers a task multiple times in parallel and then waits until they're all complete. You get the resulting data to continue with. |
Additionally, [scheduled tasks](/v3/tasks-scheduled) get automatically triggered on their schedule and [webhooks](/v3/tasks-webhooks) when receiving a webhook.
## From outside of a task
You can trigger any task from your backend code, using either `trigger()` or `batchTrigger()`.
<Note>
Do not trigger tasks directly from your frontend. If you do, you will leak your private
Trigger.dev API key to the world.
</Note>
### trigger()
Triggers a single run of a task with the payload you pass in, and any options you specify. It does NOT wait for the result, you cannot do that from outside a task.
<CodeGroup>
```ts Next.js API route
import { emailSequence } from "~/trigger/emails";
//app/email/route.ts
export async function POST(request: Request) {
//get the JSON from the request
const data = await request.json();
//trigger your task
const handle = await emailSequence.trigger({ payload: { to: data.email, name: data.name } });
//return a success response with the handle
return Response.json(handle);
}
```
```ts Remix
import { emailSequence } from "~/trigger/emails";
export async function action({ request, params }: ActionFunctionArgs) {
if (request.method.toUpperCase() !== "POST") {
return json("Method Not Allowed", { status: 405 });
}
//get the JSON from the request
const data = await request.json();
//trigger your task
const handle = await emailSequence.trigger({ payload: { to: data.email, name: data.name } });
//return a success response with the handle
return json(handle);
}
```
</CodeGroup>
### batchTrigger()
Triggers multiples runs of a task with the payloads you pass in, and any options you specify. It does NOT wait for the results, you cannot do that from outside a task.
<CodeGroup>
```ts Next.js API route
import { emailSequence } from "~/trigger/emails";
//app/email/route.ts
export async function POST(request: Request) {
//get the JSON from the request
const data = await request.json();
//batch trigger your task
const batchHandle = await emailSequence.batchTrigger({
items: data.users.map((u) => ({ payload: { to: u.email, name: u.name } })),
});
//return a success response with the handle
return Response.json(batchHandle);
}
```
```ts Remix
import { emailSequence } from "~/trigger/emails";
export async function action({ request, params }: ActionFunctionArgs) {
if (request.method.toUpperCase() !== "POST") {
return json("Method Not Allowed", { status: 405 });
}
//get the JSON from the request
const data = await request.json();
//batch trigger your task
const batchHandle = await emailSequence.batchTrigger({
items: data.users.map((u) => ({ payload: { to: u.email, name: u.name } })),
});
//return a success response with the handle
return json(batchHandle);
}
```
</CodeGroup>
## From inside a task
You can trigger tasks from other tasks using `trigger()` or `batchTrigger()`. You can also trigger and wait for the result of triggered tasks using `triggerAndWait()` and `batchTriggerAndWait()`. This is a powerful way to build complex tasks.
### trigger()
This works the same as from outside a task. You call it and you get a handle back, but it does not wait for the result.
```ts /trigger/my-task.ts
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
id: "my-task",
run: async (payload: string) => {
const handle = await myOtherTask.trigger({ payload: "some data" });
//...do other stuff
},
});
```
### batchTrigger()
This works the same as from outside a task. You call it and you get a handle back, but it does not wait for the results.
```ts /trigger/my-task.ts
import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
id: "my-task",
run: async (payload: string) => {
const batchHandle = await myOtherTask.batchTrigger({ items: [{ payload: "some data" }] });
//...do other stuff
},
});
```
### triggerAndWait()
This is where it gets interesting. You can trigger a task and then wait for the result. This is useful when you need to call a different task and then use the result to continue with your task.
```ts /trigger/parent.ts
export const parentTask = task({
id: "parent-task",
run: async (payload: string) => {
const result = await batchChildTask.triggerAndWait({ payload: "some-data" });
console.log("Result", result);
//...do stuff with the result
},
});
```
### batchTriggerAndWait()
You can batch trigger a task and wait for all the results. This is useful for the fan-out pattern, where you need to call a task multiple times and then wait for all the results to continue with your task.
```ts /trigger/nested.ts
export const batchParentTask = task({
id: "parent-task",
run: async (payload: string) => {
const results = await childTask.batchTriggerAndWait({
items: [{ payload: "item4" }, { payload: "item5" }, { payload: "item6" }],
});
console.log("Results", results);
//...do stuff with the result
},
});
```
+6
View File
@@ -0,0 +1,6 @@
---
title: "Upgrading from v2"
description: "How to upgrade your v2 jobs to v3 tasks."
---
<Snippet file="incomplete-docs.mdx" />
+16
View File
@@ -0,0 +1,16 @@
---
title: "Using APIs"
description: "You can use any Node.js library inside the run function, or do HTTP requests."
---
## Using Node.js SDKs
<Snippet file="incomplete-docs.mdx" />
## Using fetch or axios
<Snippet file="incomplete-docs.mdx" />
## Using webhooks
<Snippet file="incomplete-docs.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Vercel integration"
description: "When you deploy to Vercel, automatically deploy your associated tasks."
---
<Snippet file="coming-soon.mdx" />
+56
View File
@@ -0,0 +1,56 @@
---
title: "Versioning"
description: "We use atomic versioning to ensure that started tasks are not affected by changes to the task code."
---
A version is a bundle of tasks at a certain point in time.
## Version identifiers
Version identifiers look like this:
- `20240313.1` - March 13th, 2024, version 1
- `20240313.2` - March 13th, 2024, version 2
- `20240314.1` - March 14th, 2024, version 1
You can see there are two parts to the version identifier:
- The date (in reverse format)
- The version number
Versions numbers are incremented each time a new version is created for that date and environment. So it's possible to have `20240313.1` in both the `dev` and `prod` environments.
## Version locking
When a task run starts it is locked to the latest version of the code (for that environment). Once locked it won't change versions, even if you deploy new versions. This is to ensure that a task run is not affected by changes to the code.
### Child tasks and version locking
Trigger and wait functions version lock child task runs to the parent task run version. This ensures the results from child runs match what the parent task is expecting. If you don't wait then version locking doesn't apply.
| Trigger function | Parent task version | Child task version | isLocked |
| ----------------------- | ------------------- | ------------------ | -------- |
| `trigger()` | `20240313.2` | Latest | No |
| `batchTrigger()` | `20240313.2` | Latest | No |
| `triggerAndWait()` | `20240313.2` | `20240313.2` | Yes |
| `batchTriggerAndWait()` | `20240313.2` | `20240313.2` | Yes |
## Local development
When running the local server (using `npx trigger.dev dev`), every relevant code change automatically creates a new version of all tasks.
So a task run will continue running on the version it was locked to. We do this by spawning a new process for each task run. This ensures that the task run is not affected by changes to the code.
## Deployment
Every deployment creates a new version of all tasks for that environment.
## Retries and reattempts
When a task has an uncaught error it will [retry](/v3/errors-retrying), assuming you have not set `maxAttempts` to 0. Retries are locked to the original version of the run.
If all the attempts have failed you can start a [reattempt](/v3/reattempting-replaying). This will be version locked to the original version of the run.
## Replays
A "replay" is a new run of a task that uses the same inputs but will use the latest version of the code. This is useful when you fix a bug and want to re-run a task with the same inputs. See [replays](/v3/reattempting-replaying) for more information.
+6
View File
@@ -0,0 +1,6 @@
---
title: "Wait for event"
description: "Wait until an event has been received, then continue execution."
---
<Snippet file="coming-soon.mdx" />
+6
View File
@@ -0,0 +1,6 @@
---
title: "Wait for request"
description: "Wait until a `Request` has been received at the provided URL, then continue execution."
---
<Snippet file="coming-soon.mdx" />
+31
View File
@@ -0,0 +1,31 @@
---
title: "Wait for"
description: "Wait for a period of time, then continue execution."
---
Inside your tasks you can wait for a period of time before you want execution to continue.
```ts /trigger/long-task.ts
export const veryLongTask = task({
id: "very-long-task",
run: async (payload) => {
await wait.for({ seconds: 5 });
await wait.for({ minutes: 10 });
await wait.for({ hours: 1 });
await wait.for({ days: 1 });
await wait.for({ weeks: 1 });
await wait.for({ months: 1 });
await wait.for({ years: 1 });
},
});
```
This allows you to write linear code without having to worry about the complexity of scheduling or managing CRON jobs.
<Snippet file="v3/paused-execution-free.mdx" />
+38
View File
@@ -0,0 +1,38 @@
---
title: "Wait until"
description: "Wait until a date, then continue execution."
---
This example sends a reminder email to a user at the specified datetime.
```ts /trigger/reminder-email.ts
export const sendReminderEmail = task({
id: "send-reminder-email",
run: async (payload: { to: string; name: string; date: string }) => {
//wait until the date
await wait.until({ date: new Date(payload.date) });
//todo send email
const { data, error } = await resend.emails.send({
from: "hello@trigger.dev",
to: payload.to,
subject: "Don't forget…",
html: `<p>Hello ${payload.name},</p><p>...</p>`,
});
},
});
```
This allows you to write linear code without having to worry about the complexity of scheduling or managing CRON jobs.
<Snippet file="v3/paused-execution-free.mdx" />
## `throwIfInThePast`
You can optionally throw an error if the date is already in the past when the function is called:
```ts
await wait.until({ date: new Date(date), throwIfInThePast: true });
```
You can of course use try/catch if you want to do something special in this case.

Some files were not shown because too many files have changed in this diff Show More