|
| 1 | +--- |
| 2 | +title: "Migrating from Defer.run" |
| 3 | +description: "A guide to migrating from Defer to Trigger.dev v3" |
| 4 | +--- |
| 5 | + |
| 6 | +First of all, you should use the [Trigger.dev v3 Developer Preview](https://trigger.dev/blog/v3-developer-preview-launch/), not version 2. Version 2 is not a good choice if you're coming from Defer as the execution model is very different. [Let us know](https://) if you need v3 access. |
| 7 | + |
| 8 | +This guide highlights the differences and should help you migrate your project. |
| 9 | + |
| 10 | +## Features coming very soon |
| 11 | + |
| 12 | +You can view the full [feature matrix](/v3/feature-matrix). Here are some features you might be using in Defer that are coming this month to Trigger.dev: |
| 13 | + |
| 14 | +- [Scheduled tasks (including CRON)](/v3/tasks-scheduled) will be available in mid-April. |
| 15 | +- Triggering a task with a delay (like `assignOptions` delay in Defer) will be available soon – there is [an alternative](#delay) you can use for now. |
| 16 | + |
| 17 | +## Differences |
| 18 | + |
| 19 | +#### Local development |
| 20 | + |
| 21 | +In Defer you run your tasks locally using `npm run dev` (or other package manager). This is simple but it means dev behaved differently from production for your background tasks. |
| 22 | + |
| 23 | +With Trigger.dev you need to use our CLI to run a local server that behaves like the deployed production environment. It also means you will see your runs in the dashboard. |
| 24 | + |
| 25 | +#### Multiple tasks in a single file |
| 26 | + |
| 27 | +In Defer you needed to use a default export in a file inside your `/defer` directory. |
| 28 | + |
| 29 | +```ts /defer/longRunningTask.ts |
| 30 | +import { defer } from "@defer/client"; |
| 31 | + |
| 32 | +async function longRunningTask() { |
| 33 | + // runs a fake task for 30s |
| 34 | + await performLongRunningTask(); |
| 35 | +} |
| 36 | + |
| 37 | +export default defer(longRunningTask); |
| 38 | +``` |
| 39 | + |
| 40 | +In Trigger.dev **you use named exports** so you can have multiple tasks in a single file. |
| 41 | + |
| 42 | +```ts /trigger/someTasks.ts |
| 43 | +export const longRunningTask = task({ |
| 44 | + id: "longRunningTask", |
| 45 | + run: async (payload: any) => { |
| 46 | + //...do stuff |
| 47 | + }, |
| 48 | +}); |
| 49 | + |
| 50 | +export const otherTask = task({ |
| 51 | + id: "otherTask", |
| 52 | + run: async (payload: any) => { |
| 53 | + //...do different stuff |
| 54 | + }, |
| 55 | +}); |
| 56 | +``` |
| 57 | + |
| 58 | +#### Triggering your tasks |
| 59 | + |
| 60 | +In Defer, you wrapped your existing function in `defer()`. Then for simple cases you could just call the function. In other cases, like when you wanted to have a delay you needed to use `assignOptions` to create a new function. |
| 61 | + |
| 62 | +```ts /app/actions/actions.ts |
| 63 | +"use server"; |
| 64 | + |
| 65 | +import longRunningTask from "@/defer/longRunningTask"; |
| 66 | + |
| 67 | +export async function runLongRunningTask() { |
| 68 | + return await longRunningTask(); |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +In Trigger.dev your logic goes in the `run` function of a task. You can then `trigger` and `batchTrigger` that task, with a payload and options. |
| 73 | + |
| 74 | +```ts /app/actions/actions.ts |
| 75 | +"use server"; |
| 76 | + |
| 77 | +import { longRunningTask } from "@/trigger/someTasks"; |
| 78 | + |
| 79 | +export async function runLongRunningTask() { |
| 80 | + return await longRunningTask.trigger({ payload: { foo: "bar" } }); |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +#### `wait` |
| 85 | + |
| 86 | +In Trigger.dev you can use the [wait](/v3/wait) functions to freeze execution of your code until a later date (it can be months later). You won't pay while it's frozen and the state is restored exactly when it wakes (using a technology called CRIU). |
| 87 | + |
| 88 | +```ts |
| 89 | +//In Defer you could use "sleep" but that would keep your function running. |
| 90 | +await sleep(1000 * 60 * 5); // 5 minutes but you'd pay for it. |
| 91 | + |
| 92 | +//In Trigger.dev you can use wait. We freeze execution if it's more than 30s |
| 93 | +await wait.for({ seconds: 5 }); |
| 94 | +await wait.for({ minutes: 10 }); |
| 95 | +await wait.for({ hours: 1 }); |
| 96 | +await wait.for({ days: 1 }); |
| 97 | +await wait.for({ weeks: 1 }); |
| 98 | +await wait.for({ months: 1 }); |
| 99 | +await wait.for({ years: 1 }); |
| 100 | + |
| 101 | +//you can wait for a date too |
| 102 | +await wait.until({ date: aFutureDate }); |
| 103 | +``` |
| 104 | + |
| 105 | +#### delay the start of a run |
| 106 | + |
| 107 | +In Defer you can do this: |
| 108 | + |
| 109 | +```ts |
| 110 | +const delayedRun = assignOptions(someTask, { delay: "10s" }); |
| 111 | +await delayedRun(); |
| 112 | +``` |
| 113 | + |
| 114 | +There will be a nice way to do this soon when you call `trigger()` but for now you can use `wait` to get the same behavior: |
| 115 | + |
| 116 | +```ts |
| 117 | +export const helloWorld = task({ |
| 118 | + id: "hello-world", |
| 119 | + run: async (payload: { delayUntil?: Date; delayForSeconds?: number }) => { |
| 120 | + if (payload.delayUntil) { |
| 121 | + await wait.until({ date: payload.delayUntil }); |
| 122 | + } |
| 123 | + |
| 124 | + if (payload.delayForSeconds) { |
| 125 | + await wait.for({ seconds: payload.delayForSeconds }); |
| 126 | + } |
| 127 | + |
| 128 | + //do stuff |
| 129 | + }, |
| 130 | +}); |
| 131 | +``` |
| 132 | + |
| 133 | +## How to migrate |
| 134 | + |
| 135 | +### 1. Get Trigger.dev working in your project |
| 136 | + |
| 137 | +<Steps> |
| 138 | + |
| 139 | +<Step title="Create an organization on Trigger.dev"> |
| 140 | + |
| 141 | +1. Go to the [Trigger.dev Cloud](https://cloud.trigger.dev) |
| 142 | +2. Create an account |
| 143 | +3. Create an organization with a project (this will be a version 2 project) |
| 144 | +4. [DM us on Discord](https://trigger.dev/discord) or [fill in this form](https://trigger.dev/v3-early-access) and mention Defer in the company name. |
| 145 | + |
| 146 | +We will grant you v3 access. |
| 147 | + |
| 148 | +</Step> |
| 149 | + |
| 150 | +<Step> |
| 151 | + |
| 152 | +You need to create a v3 project. |
| 153 | + |
| 154 | +1. Go to the Projects page |
| 155 | + |
| 156 | + |
| 157 | + |
| 158 | +2. Click "Create a new project" |
| 159 | + |
| 160 | + |
| 161 | + |
| 162 | +3. Make sure you select "Version 3" from the dropdown! |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | +<Warning> |
| 167 | + If you don't see a dropdown then you don't have v3 access. [Fill in this |
| 168 | + form](https://trigger.dev/v3-early-access) and mention Defer in the company name. |
| 169 | +</Warning> |
| 170 | + |
| 171 | +</Step> |
| 172 | + |
| 173 | +<Snippet file="v3/step-cli-init.mdx" /> |
| 174 | +<Snippet file="v3/step-cli-dev.mdx" /> |
| 175 | +<Snippet file="v3/step-run-test.mdx" /> |
| 176 | +<Snippet file="v3/step-view-run.mdx" /> |
| 177 | + |
| 178 | +</Steps> |
| 179 | + |
| 180 | +### 2. Migrate your Defer functions to Trigger.dev tasks |
| 181 | + |
| 182 | +#### Example 1: Simple function |
| 183 | + |
| 184 | +In Defer you might have a function like this. |
| 185 | + |
| 186 | +<CodeBlock> |
| 187 | + |
| 188 | +```ts /defer/longRunningTask.ts |
| 189 | +import { performLongRunningTask } from "@/utils/performLongRunningTask"; |
| 190 | +import { defer } from "@defer/client"; |
| 191 | + |
| 192 | +async function longRunningTask() { |
| 193 | + // runs a fake task for 30s |
| 194 | + await performLongRunningTask(); |
| 195 | +} |
| 196 | + |
| 197 | +export default defer(longRunningTask, { |
| 198 | + concurrency: 2, // want maximum 2 executions of this function in parallel |
| 199 | + retry: 5, // adding retry to recover from potential network issues or rate limiting |
| 200 | +}); |
| 201 | +``` |
| 202 | + |
| 203 | +```ts /app/actions/actions.ts |
| 204 | +"use server"; |
| 205 | + |
| 206 | +import longRunningTask from "@/defer/longRunningTask"; |
| 207 | + |
| 208 | +export async function runLongRunningTask() { |
| 209 | + return await longRunningTask(); |
| 210 | +} |
| 211 | +``` |
| 212 | + |
| 213 | +</CodeBlock> |
| 214 | + |
| 215 | +In Trigger.dev it looks like this: |
| 216 | + |
| 217 | +<CodeBlock> |
| 218 | + |
| 219 | +```ts /trigger/someTasks.ts |
| 220 | +import { performLongRunningTask } from "@/utils/performLongRunningTask"; |
| 221 | +import { task } from "@trigger.dev/sdk/v3"; |
| 222 | + |
| 223 | +//named export |
| 224 | +export const longRunningTask = task({ |
| 225 | + //a unique and stable ID so you can refactor the function name |
| 226 | + id: "long-running-task", |
| 227 | + queue: { |
| 228 | + concurrencyLimit: 2, // want maximum 2 executions of this function in parallel |
| 229 | + }, |
| 230 | + retry: { |
| 231 | + maxAttempts: 5, // adding retry to recover from potential network issues or rate limiting |
| 232 | + }, |
| 233 | + run: async (payload: any) => { |
| 234 | + // runs a fake task for 30s |
| 235 | + await performLongRunningTask(); |
| 236 | + }, |
| 237 | +}); |
| 238 | +``` |
| 239 | + |
| 240 | +```ts /app/actions/actions.ts |
| 241 | +"use server"; |
| 242 | + |
| 243 | +import longRunningTask from "@/defer/longRunningTask"; |
| 244 | + |
| 245 | +export async function runLongRunningTask() { |
| 246 | + return await longRunningTask(); |
| 247 | +} |
| 248 | +``` |
| 249 | + |
| 250 | +</CodeBlock> |
| 251 | + |
| 252 | +<Warning> |
| 253 | + You need to set your `TRIGGER_SECRET_KEY` environment variable in your `.env` or `.env.local` file |
| 254 | + to trigger tasks from your code. See the [API keys page](/v3/apikeys) for more information. |
| 255 | +</Warning> |
| 256 | + |
| 257 | +#### Example 2: A CRON task |
| 258 | + |
| 259 | +<Warning> |
| 260 | + "Scheduled" tasks will be available by mid-April. This will allow you to replace Defer CRON tasks. |
| 261 | +</Warning> |
0 commit comments