@trigger.dev/sdk 4.5.0-rc.5 → 4.5.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/dist/commonjs/v3/ai.d.ts +178 -5
  2. package/dist/commonjs/v3/ai.js +603 -119
  3. package/dist/commonjs/v3/ai.js.map +1 -1
  4. package/dist/commonjs/v3/chat-client.js +3 -0
  5. package/dist/commonjs/v3/chat-client.js.map +1 -1
  6. package/dist/commonjs/v3/chat-react.js +10 -7
  7. package/dist/commonjs/v3/chat-react.js.map +1 -1
  8. package/dist/commonjs/v3/chat-server.d.ts +8 -0
  9. package/dist/commonjs/v3/chat-server.js +32 -10
  10. package/dist/commonjs/v3/chat-server.js.map +1 -1
  11. package/dist/commonjs/v3/chat-server.test.js +51 -0
  12. package/dist/commonjs/v3/chat-server.test.js.map +1 -1
  13. package/dist/commonjs/v3/chat.js +34 -6
  14. package/dist/commonjs/v3/chat.js.map +1 -1
  15. package/dist/commonjs/v3/chat.test.js +53 -0
  16. package/dist/commonjs/v3/chat.test.js.map +1 -1
  17. package/dist/commonjs/v3/createStartSessionAction.test.js +30 -0
  18. package/dist/commonjs/v3/createStartSessionAction.test.js.map +1 -1
  19. package/dist/commonjs/v3/sessions.d.ts +11 -6
  20. package/dist/commonjs/v3/sessions.js +10 -5
  21. package/dist/commonjs/v3/sessions.js.map +1 -1
  22. package/dist/commonjs/v3/test/mock-chat-agent.d.ts +6 -0
  23. package/dist/commonjs/v3/test/mock-chat-agent.js +1 -0
  24. package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
  25. package/dist/commonjs/version.js +1 -1
  26. package/dist/esm/v3/ai.d.ts +178 -5
  27. package/dist/esm/v3/ai.js +603 -120
  28. package/dist/esm/v3/ai.js.map +1 -1
  29. package/dist/esm/v3/chat-client.js +3 -0
  30. package/dist/esm/v3/chat-client.js.map +1 -1
  31. package/dist/esm/v3/chat-react.js +10 -7
  32. package/dist/esm/v3/chat-react.js.map +1 -1
  33. package/dist/esm/v3/chat-server.d.ts +8 -0
  34. package/dist/esm/v3/chat-server.js +32 -10
  35. package/dist/esm/v3/chat-server.js.map +1 -1
  36. package/dist/esm/v3/chat-server.test.js +51 -0
  37. package/dist/esm/v3/chat-server.test.js.map +1 -1
  38. package/dist/esm/v3/chat.js +34 -6
  39. package/dist/esm/v3/chat.js.map +1 -1
  40. package/dist/esm/v3/chat.test.js +53 -0
  41. package/dist/esm/v3/chat.test.js.map +1 -1
  42. package/dist/esm/v3/createStartSessionAction.test.js +30 -0
  43. package/dist/esm/v3/createStartSessionAction.test.js.map +1 -1
  44. package/dist/esm/v3/sessions.d.ts +11 -6
  45. package/dist/esm/v3/sessions.js +10 -5
  46. package/dist/esm/v3/sessions.js.map +1 -1
  47. package/dist/esm/v3/test/mock-chat-agent.d.ts +6 -0
  48. package/dist/esm/v3/test/mock-chat-agent.js +1 -0
  49. package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
  50. package/dist/esm/version.js +1 -1
  51. package/docs/ai/prompts.mdx +430 -0
  52. package/docs/ai-chat/actions.mdx +115 -0
  53. package/docs/ai-chat/anatomy.mdx +71 -0
  54. package/docs/ai-chat/backend.mdx +817 -0
  55. package/docs/ai-chat/background-injection.mdx +221 -0
  56. package/docs/ai-chat/changelog.mdx +850 -0
  57. package/docs/ai-chat/chat-local.mdx +174 -0
  58. package/docs/ai-chat/client-protocol.mdx +1081 -0
  59. package/docs/ai-chat/compaction.mdx +411 -0
  60. package/docs/ai-chat/custom-agents.mdx +364 -0
  61. package/docs/ai-chat/error-handling.mdx +415 -0
  62. package/docs/ai-chat/fast-starts.mdx +672 -0
  63. package/docs/ai-chat/frontend.mdx +580 -0
  64. package/docs/ai-chat/how-it-works.mdx +230 -0
  65. package/docs/ai-chat/lifecycle-hooks.mdx +530 -0
  66. package/docs/ai-chat/mcp.mdx +101 -0
  67. package/docs/ai-chat/overview.mdx +90 -0
  68. package/docs/ai-chat/patterns/branching-conversations.mdx +284 -0
  69. package/docs/ai-chat/patterns/code-sandbox.mdx +126 -0
  70. package/docs/ai-chat/patterns/database-persistence.mdx +414 -0
  71. package/docs/ai-chat/patterns/human-in-the-loop.mdx +275 -0
  72. package/docs/ai-chat/patterns/large-payloads.mdx +169 -0
  73. package/docs/ai-chat/patterns/oom-resilience.mdx +120 -0
  74. package/docs/ai-chat/patterns/persistence-and-replay.mdx +211 -0
  75. package/docs/ai-chat/patterns/recovery-boot.mdx +230 -0
  76. package/docs/ai-chat/patterns/skills.mdx +221 -0
  77. package/docs/ai-chat/patterns/sub-agents.mdx +383 -0
  78. package/docs/ai-chat/patterns/tool-result-auditing.mdx +148 -0
  79. package/docs/ai-chat/patterns/trusted-edge-signals.mdx +337 -0
  80. package/docs/ai-chat/patterns/version-upgrades.mdx +172 -0
  81. package/docs/ai-chat/pending-messages.mdx +343 -0
  82. package/docs/ai-chat/prompt-caching.mdx +206 -0
  83. package/docs/ai-chat/quick-start.mdx +161 -0
  84. package/docs/ai-chat/reference.mdx +909 -0
  85. package/docs/ai-chat/server-chat.mdx +263 -0
  86. package/docs/ai-chat/sessions.mdx +333 -0
  87. package/docs/ai-chat/testing.mdx +682 -0
  88. package/docs/ai-chat/tools.mdx +191 -0
  89. package/docs/ai-chat/types.mdx +242 -0
  90. package/docs/ai-chat/upgrade-guide.mdx +515 -0
  91. package/docs/apikeys.mdx +54 -0
  92. package/docs/building-with-ai.mdx +261 -0
  93. package/docs/bulk-actions.mdx +49 -0
  94. package/docs/changelog.mdx +6 -0
  95. package/docs/cli-deploy-commands.mdx +9 -0
  96. package/docs/cli-dev-commands.mdx +9 -0
  97. package/docs/cli-dev.mdx +8 -0
  98. package/docs/cli-init-commands.mdx +58 -0
  99. package/docs/cli-introduction.mdx +25 -0
  100. package/docs/cli-list-profiles-commands.mdx +42 -0
  101. package/docs/cli-login-commands.mdx +33 -0
  102. package/docs/cli-logout-commands.mdx +33 -0
  103. package/docs/cli-preview-archive.mdx +59 -0
  104. package/docs/cli-promote-commands.mdx +9 -0
  105. package/docs/cli-switch.mdx +43 -0
  106. package/docs/cli-update-commands.mdx +42 -0
  107. package/docs/cli-whoami-commands.mdx +33 -0
  108. package/docs/community.mdx +6 -0
  109. package/docs/config/config-file.mdx +602 -0
  110. package/docs/config/extensions/additionalFiles.mdx +38 -0
  111. package/docs/config/extensions/additionalPackages.mdx +40 -0
  112. package/docs/config/extensions/aptGet.mdx +34 -0
  113. package/docs/config/extensions/audioWaveform.mdx +20 -0
  114. package/docs/config/extensions/custom.mdx +380 -0
  115. package/docs/config/extensions/emitDecoratorMetadata.mdx +29 -0
  116. package/docs/config/extensions/esbuildPlugin.mdx +31 -0
  117. package/docs/config/extensions/ffmpeg.mdx +45 -0
  118. package/docs/config/extensions/lightpanda.mdx +56 -0
  119. package/docs/config/extensions/overview.mdx +67 -0
  120. package/docs/config/extensions/playwright.mdx +195 -0
  121. package/docs/config/extensions/prismaExtension.mdx +1014 -0
  122. package/docs/config/extensions/puppeteer.mdx +30 -0
  123. package/docs/config/extensions/pythonExtension.mdx +182 -0
  124. package/docs/config/extensions/syncEnvVars.mdx +291 -0
  125. package/docs/context.mdx +235 -0
  126. package/docs/database-connections.mdx +213 -0
  127. package/docs/deploy-environment-variables.mdx +435 -0
  128. package/docs/deployment/atomic-deployment.mdx +172 -0
  129. package/docs/deployment/overview.mdx +257 -0
  130. package/docs/deployment/preview-branches.mdx +224 -0
  131. package/docs/errors-retrying.mdx +379 -0
  132. package/docs/github-actions.mdx +222 -0
  133. package/docs/github-integration.mdx +136 -0
  134. package/docs/github-repo.mdx +8 -0
  135. package/docs/help-email.mdx +6 -0
  136. package/docs/help-slack.mdx +11 -0
  137. package/docs/hidden-tasks.mdx +56 -0
  138. package/docs/how-it-works.mdx +454 -0
  139. package/docs/how-to-reduce-your-spend.mdx +217 -0
  140. package/docs/idempotency.mdx +504 -0
  141. package/docs/introduction.mdx +223 -0
  142. package/docs/limits.mdx +241 -0
  143. package/docs/logging.mdx +195 -0
  144. package/docs/machines.mdx +952 -0
  145. package/docs/manual-setup.mdx +632 -0
  146. package/docs/mcp-agent-rules.mdx +41 -0
  147. package/docs/mcp-introduction.mdx +385 -0
  148. package/docs/mcp-tools.mdx +273 -0
  149. package/docs/migrating-from-v3.mdx +334 -0
  150. package/docs/observability/dashboards.mdx +102 -0
  151. package/docs/observability/query.mdx +585 -0
  152. package/docs/open-source-contributing.mdx +16 -0
  153. package/docs/open-source-self-hosting.mdx +541 -0
  154. package/docs/private-networking/aws-console-setup.mdx +304 -0
  155. package/docs/private-networking/overview.mdx +144 -0
  156. package/docs/private-networking/troubleshooting.mdx +78 -0
  157. package/docs/queue-concurrency.mdx +354 -0
  158. package/docs/quick-start.mdx +97 -0
  159. package/docs/realtime/auth.mdx +208 -0
  160. package/docs/realtime/backend/overview.mdx +45 -0
  161. package/docs/realtime/backend/streams.mdx +418 -0
  162. package/docs/realtime/backend/subscribe.mdx +225 -0
  163. package/docs/realtime/how-it-works.mdx +94 -0
  164. package/docs/realtime/overview.mdx +63 -0
  165. package/docs/realtime/react-hooks/overview.mdx +73 -0
  166. package/docs/realtime/react-hooks/streams.mdx +449 -0
  167. package/docs/realtime/react-hooks/subscribe.mdx +674 -0
  168. package/docs/realtime/react-hooks/swr.mdx +87 -0
  169. package/docs/realtime/react-hooks/triggering.mdx +194 -0
  170. package/docs/realtime/react-hooks/use-wait-token.mdx +34 -0
  171. package/docs/realtime/run-object.mdx +174 -0
  172. package/docs/replaying.mdx +72 -0
  173. package/docs/request-feature.mdx +6 -0
  174. package/docs/roadmap.mdx +6 -0
  175. package/docs/run-tests.mdx +20 -0
  176. package/docs/run-usage.mdx +113 -0
  177. package/docs/runs/heartbeats.mdx +38 -0
  178. package/docs/runs/max-duration.mdx +139 -0
  179. package/docs/runs/metadata.mdx +734 -0
  180. package/docs/runs/priority.mdx +31 -0
  181. package/docs/runs.mdx +396 -0
  182. package/docs/self-hosting/docker.mdx +458 -0
  183. package/docs/self-hosting/env/supervisor.mdx +74 -0
  184. package/docs/self-hosting/env/webapp.mdx +276 -0
  185. package/docs/self-hosting/kubernetes.mdx +601 -0
  186. package/docs/self-hosting/overview.mdx +108 -0
  187. package/docs/skills.mdx +85 -0
  188. package/docs/tags.mdx +120 -0
  189. package/docs/tasks/overview.mdx +697 -0
  190. package/docs/tasks/scheduled.mdx +382 -0
  191. package/docs/tasks/schemaTask.mdx +413 -0
  192. package/docs/tasks/streams.mdx +884 -0
  193. package/docs/triggering.mdx +1320 -0
  194. package/docs/troubleshooting-alerts.mdx +385 -0
  195. package/docs/troubleshooting-debugging-in-vscode.mdx +8 -0
  196. package/docs/troubleshooting-github-issues.mdx +6 -0
  197. package/docs/troubleshooting-uptime-status.mdx +6 -0
  198. package/docs/troubleshooting.mdx +398 -0
  199. package/docs/upgrading-packages.mdx +80 -0
  200. package/docs/vercel-integration.mdx +207 -0
  201. package/docs/versioning.mdx +56 -0
  202. package/docs/video-walkthrough.mdx +23 -0
  203. package/docs/wait-for-token.mdx +540 -0
  204. package/docs/wait-for.mdx +42 -0
  205. package/docs/wait-until.mdx +53 -0
  206. package/docs/wait.mdx +18 -0
  207. package/docs/writing-tasks-introduction.mdx +33 -0
  208. package/package.json +10 -6
  209. package/skills/trigger-authoring-chat-agent/SKILL.md +296 -0
  210. package/skills/trigger-authoring-tasks/SKILL.md +254 -0
  211. package/skills/trigger-chat-agent-advanced/SKILL.md +368 -0
  212. package/skills/trigger-cost-savings/SKILL.md +116 -0
  213. package/skills/trigger-realtime-and-frontend/SKILL.md +276 -0
@@ -0,0 +1,379 @@
1
+ ---
2
+ title: "Errors & Retrying"
3
+ description: "How to deal with errors and write reliable tasks."
4
+ ---
5
+
6
+ import OpenaiRetry from "/snippets/code/openai-retry.mdx";
7
+
8
+ When an uncaught error is thrown inside your task, that task attempt will fail.
9
+
10
+ You can configure retrying in two ways:
11
+
12
+ 1. In your [trigger.config file](/config/config-file) you can set the default retrying behavior for all tasks.
13
+ 2. On each task you can set the retrying behavior.
14
+
15
+ <Note>Task-level retry settings override the defaults in your `trigger.config` file.</Note>
16
+
17
+ <Note>
18
+ By default when you create your project using the CLI init command we disabled retrying in the DEV
19
+ environment. You can enable it in your [trigger.config file](/config/config-file).
20
+ </Note>
21
+
22
+ ## A simple example with OpenAI
23
+
24
+ This task will retry 10 times with exponential backoff.
25
+
26
+ - `openai.chat.completions.create()` can throw an error.
27
+ - The result can be empty and we want to try again. So we manually throw an error.
28
+
29
+ <OpenaiRetry />
30
+
31
+ ## Combining tasks
32
+
33
+ One way to gain reliability is to break your work into smaller tasks and [trigger](/triggering) them from each other. Each task can have its own retrying behavior:
34
+
35
+ ```ts /trigger/multiple-tasks.ts
36
+ import { task } from "@trigger.dev/sdk";
37
+
38
+ export const myTask = task({
39
+ id: "my-task",
40
+ retry: {
41
+ maxAttempts: 10,
42
+ },
43
+ run: async (payload: string) => {
44
+ const result = await otherTask.triggerAndWait("some data");
45
+ //...do other stuff
46
+ },
47
+ });
48
+
49
+ export const otherTask = task({
50
+ id: "other-task",
51
+ retry: {
52
+ maxAttempts: 5,
53
+ },
54
+ run: async (payload: string) => {
55
+ return {
56
+ foo: "bar",
57
+ };
58
+ },
59
+ });
60
+ ```
61
+
62
+ Another benefit of this approach is that you can view the logs and retry each task independently from the dashboard.
63
+
64
+ ## Retrying smaller parts of a task
65
+
66
+ Another complimentary strategy is to perform retrying inside of your task.
67
+
68
+ 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.
69
+
70
+ ### retry.onThrow()
71
+
72
+ You can retry a block of code that can throw an error, with the same retry settings as a task.
73
+
74
+ ```ts /trigger/retry-on-throw.ts
75
+ import { task, logger, retry } from "@trigger.dev/sdk";
76
+
77
+ export const retryOnThrow = task({
78
+ id: "retry-on-throw",
79
+ run: async (payload: any) => {
80
+ //Will retry up to 3 times. If it fails 3 times it will throw.
81
+ const result = await retry.onThrow(
82
+ async ({ attempt }) => {
83
+ //throw on purpose the first 2 times, obviously this is a contrived example
84
+ if (attempt < 3) throw new Error("failed");
85
+ //...
86
+ return {
87
+ foo: "bar",
88
+ };
89
+ },
90
+ { maxAttempts: 3, randomize: false }
91
+ );
92
+
93
+ //this will log out after 3 attempts of retry.onThrow
94
+ logger.info("Result", { result });
95
+ },
96
+ });
97
+ ```
98
+
99
+ <Note>
100
+ If all of the attempts with `retry.onThrow` fail, an error will be thrown. You can catch this or
101
+ let it cause a retry of the entire task.
102
+ </Note>
103
+
104
+ ### retry.fetch()
105
+
106
+ You can use `fetch`, `axios`, or any other library in your code.
107
+
108
+ But we do provide a convenient function to perform HTTP requests with conditional retrying based on the response:
109
+
110
+ ```ts /trigger/retry-fetch.ts
111
+ import { task, logger, retry } from "@trigger.dev/sdk";
112
+
113
+ export const taskWithFetchRetries = task({
114
+ id: "task-with-fetch-retries",
115
+ run: async ({ payload, ctx }) => {
116
+ //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.
117
+ const headersResponse = await retry.fetch("http://my.host/test-headers", {
118
+ retry: {
119
+ byStatus: {
120
+ "429": {
121
+ strategy: "headers",
122
+ limitHeader: "x-ratelimit-limit",
123
+ remainingHeader: "x-ratelimit-remaining",
124
+ resetHeader: "x-ratelimit-reset",
125
+ resetFormat: "unix_timestamp_in_ms",
126
+ },
127
+ },
128
+ },
129
+ });
130
+ const json = await headersResponse.json();
131
+ logger.info("Fetched headers response", { json });
132
+
133
+ //if the Response is a 500-599 (issue with the server you're calling), it will retry up to 10 times with exponential backoff
134
+ const backoffResponse = await retry.fetch("http://my.host/test-backoff", {
135
+ retry: {
136
+ byStatus: {
137
+ "500-599": {
138
+ strategy: "backoff",
139
+ maxAttempts: 10,
140
+ factor: 2,
141
+ minTimeoutInMs: 1_000,
142
+ maxTimeoutInMs: 30_000,
143
+ randomize: false,
144
+ },
145
+ },
146
+ },
147
+ });
148
+ const json2 = await backoffResponse.json();
149
+ logger.info("Fetched backoff response", { json2 });
150
+
151
+ //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
152
+ const timeoutResponse = await retry.fetch("https://httpbin.org/delay/2", {
153
+ timeoutInMs: 1000,
154
+ retry: {
155
+ timeout: {
156
+ maxAttempts: 5,
157
+ factor: 1.8,
158
+ minTimeoutInMs: 500,
159
+ maxTimeoutInMs: 30_000,
160
+ randomize: false,
161
+ },
162
+ },
163
+ });
164
+ const json3 = await timeoutResponse.json();
165
+ logger.info("Fetched timeout response", { json3 });
166
+
167
+ return {
168
+ result: "success",
169
+ payload,
170
+ json,
171
+ json2,
172
+ json3,
173
+ };
174
+ },
175
+ });
176
+ ```
177
+
178
+ <Note>
179
+ If all of the attempts with `retry.fetch` fail, an error will be thrown. You can catch this or let
180
+ it cause a retry of the entire task.
181
+ </Note>
182
+
183
+ ## Advanced error handling and retrying
184
+
185
+ We provide a `catchError` callback on the task and in your `trigger.config` file. This gets called when an uncaught error is thrown in your task.
186
+
187
+ You can
188
+
189
+ - Inspect the error, log it, and return a different error if you'd like.
190
+ - Modify the retrying behavior based on the error, payload, context, etc.
191
+
192
+ 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.
193
+
194
+ ### OpenAI error handling example
195
+
196
+ OpenAI calls can fail for a lot of reasons and the ideal retry behavior is different for each.
197
+
198
+ In this complicated example:
199
+
200
+ - We skip retrying if there's no Response status.
201
+ - We skip retrying if you've run out of credits.
202
+ - If there are no Response headers we let the normal retrying logic handle it (return undefined).
203
+ - If we've run out of requests or tokens we retry at the time specified in the headers.
204
+
205
+ <CodeGroup>
206
+
207
+ ```ts tasks.ts
208
+ import { task } from "@trigger.dev/sdk";
209
+ import { calculateISO8601DurationOpenAIVariantResetAt, openai } from "./openai.js";
210
+
211
+ export const openaiTask = task({
212
+ id: "openai-task",
213
+ retry: {
214
+ maxAttempts: 1,
215
+ },
216
+ run: async (payload: { prompt: string }) => {
217
+ const chatCompletion = await openai.chat.completions.create({
218
+ messages: [{ role: "user", content: payload.prompt }],
219
+ model: "gpt-3.5-turbo",
220
+ });
221
+
222
+ return chatCompletion.choices[0].message.content;
223
+ },
224
+ catchError: async ({ payload, error, ctx, retryAt }) => {
225
+ if (error instanceof OpenAI.APIError) {
226
+ if (!error.status) {
227
+ return {
228
+ skipRetrying: true,
229
+ };
230
+ }
231
+
232
+ if (error.status === 429 && error.type === "insufficient_quota") {
233
+ return {
234
+ skipRetrying: true,
235
+ };
236
+ }
237
+
238
+ if (!error.headers) {
239
+ //returning undefined means the normal retrying logic will be used
240
+ return;
241
+ }
242
+
243
+ const remainingRequests = error.headers["x-ratelimit-remaining-requests"];
244
+ const requestResets = error.headers["x-ratelimit-reset-requests"];
245
+
246
+ if (typeof remainingRequests === "string" && Number(remainingRequests) === 0) {
247
+ return {
248
+ retryAt: calculateISO8601DurationOpenAIVariantResetAt(requestResets),
249
+ };
250
+ }
251
+
252
+ const remainingTokens = error.headers["x-ratelimit-remaining-tokens"];
253
+ const tokensResets = error.headers["x-ratelimit-reset-tokens"];
254
+
255
+ if (typeof remainingTokens === "string" && Number(remainingTokens) === 0) {
256
+ return {
257
+ retryAt: calculateISO8601DurationOpenAIVariantResetAt(tokensResets),
258
+ };
259
+ }
260
+ }
261
+ },
262
+ });
263
+ ```
264
+
265
+ ```ts openai.ts
266
+ import { OpenAI } from "openai";
267
+
268
+ export const openai = new OpenAI({ apiKey: env.OPENAI_API_KEY });
269
+
270
+ export function calculateISO8601DurationOpenAIVariantResetAt(
271
+ resets: string,
272
+ now: Date = new Date()
273
+ ): Date | undefined {
274
+ // Check if the input is null or undefined
275
+ if (!resets) return undefined;
276
+
277
+ // Regular expression to match the duration string pattern
278
+ const pattern = /^(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?(?:(\d+)ms)?$/;
279
+ const match = resets.match(pattern);
280
+
281
+ // If the string doesn't match the expected format, return undefined
282
+ if (!match) return undefined;
283
+
284
+ // Extract days, hours, minutes, seconds, and milliseconds from the string
285
+ const days = parseInt(match[1] ?? "0", 10) || 0;
286
+ const hours = parseInt(match[2] ?? "0", 10) || 0;
287
+ const minutes = parseInt(match[3] ?? "0", 10) || 0;
288
+ const seconds = parseFloat(match[4] ?? "0") || 0;
289
+ const milliseconds = parseInt(match[5] ?? "0", 10) || 0;
290
+
291
+ // Calculate the future date based on the current date plus the extracted time
292
+ const resetAt = new Date(now);
293
+ resetAt.setDate(resetAt.getDate() + days);
294
+ resetAt.setHours(resetAt.getHours() + hours);
295
+ resetAt.setMinutes(resetAt.getMinutes() + minutes);
296
+ resetAt.setSeconds(resetAt.getSeconds() + Math.floor(seconds));
297
+ resetAt.setMilliseconds(
298
+ resetAt.getMilliseconds() + (seconds - Math.floor(seconds)) * 1000 + milliseconds
299
+ );
300
+
301
+ return resetAt;
302
+ }
303
+ ```
304
+
305
+ </CodeGroup>
306
+
307
+ ## Preventing retries
308
+
309
+ ### Using `AbortTaskRunError`
310
+
311
+ You can prevent retries by throwing an `AbortTaskRunError`. This will fail the task attempt and disable retrying.
312
+
313
+ ```ts /trigger/myTasks.ts
314
+ import { task, AbortTaskRunError } from "@trigger.dev/sdk";
315
+
316
+ export const openaiTask = task({
317
+ id: "openai-task",
318
+ run: async (payload: { prompt: string }) => {
319
+ //if this fails, it will throw an error and stop retrying
320
+ const chatCompletion = await openai.chat.completions.create({
321
+ messages: [{ role: "user", content: payload.prompt }],
322
+ model: "gpt-3.5-turbo",
323
+ });
324
+
325
+ if (chatCompletion.choices[0]?.message.content === undefined) {
326
+ // If OpenAI returns an empty response, abort retrying
327
+ throw new AbortTaskRunError("OpenAI call failed");
328
+ }
329
+
330
+ return chatCompletion.choices[0].message.content;
331
+ },
332
+ });
333
+ ```
334
+
335
+ ### Using try/catch
336
+
337
+ 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.
338
+
339
+ ```ts /trigger/myTasks.ts
340
+ import { task } from "@trigger.dev/sdk";
341
+
342
+ export const openaiTask = task({
343
+ id: "openai-task",
344
+ run: async (payload: { prompt: string }) => {
345
+ try {
346
+ //if this fails, it will throw an error and retry
347
+ const chatCompletion = await openai.chat.completions.create({
348
+ messages: [{ role: "user", content: payload.prompt }],
349
+ model: "gpt-3.5-turbo",
350
+ });
351
+
352
+ if (chatCompletion.choices[0]?.message.content === undefined) {
353
+ //sometimes OpenAI returns an empty response, let's retry by throwing an error
354
+ throw new Error("OpenAI call failed");
355
+ }
356
+
357
+ return chatCompletion.choices[0].message.content;
358
+ } catch (error) {
359
+ //use Replicate if OpenAI fails
360
+ const prediction = await replicate.run(
361
+ "meta/llama-2-70b-chat:02e509c789964a7ea8736978a43525956ef40397be9033abf9fd2badfe68c9e3",
362
+ {
363
+ input: {
364
+ prompt: payload.prompt,
365
+ max_new_tokens: 250,
366
+ },
367
+ }
368
+ );
369
+
370
+ if (prediction.output === undefined) {
371
+ //retry if Replicate fails
372
+ throw new Error("Replicate call failed");
373
+ }
374
+
375
+ return prediction.output;
376
+ }
377
+ },
378
+ });
379
+ ```
@@ -0,0 +1,222 @@
1
+ ---
2
+ title: "CI / GitHub Actions"
3
+ description: "You can easily deploy your tasks with GitHub actions and other CI environments."
4
+ ---
5
+
6
+ The instructions below are specific to GitHub Actions, but the same concepts can be used with other CI systems.
7
+
8
+ <Tip>
9
+ Check out our new [GitHub integration](/github-integration) for automatic deployments, without adding any GitHub Actions workflows.
10
+ </Tip>
11
+
12
+ ## GitHub Actions example
13
+
14
+ This simple GitHub action workflow will deploy your Trigger.dev tasks when new code is pushed to the `main` branch and the `trigger` directory has changes in it.
15
+
16
+ <Warning>
17
+ The deploy step will fail if any version mismatches are detected. Please see the [version
18
+ pinning](/github-actions#version-pinning) section for more details.
19
+ </Warning>
20
+
21
+ <CodeGroup>
22
+
23
+ ```yaml .github/workflows/release-trigger-prod.yml
24
+ name: Deploy to Trigger.dev (prod)
25
+
26
+ on:
27
+ push:
28
+ branches:
29
+ - main
30
+
31
+ jobs:
32
+ deploy:
33
+ runs-on: ubuntu-latest
34
+
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+
38
+ - name: Use Node.js 20.x
39
+ uses: actions/setup-node@v4
40
+ with:
41
+ node-version: "20.x"
42
+
43
+ - name: Install dependencies
44
+ run: npm install
45
+
46
+ - name: 🚀 Deploy Trigger.dev
47
+ env:
48
+ TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
49
+ run: |
50
+ npx trigger.dev@latest deploy
51
+ ```
52
+
53
+ ```yaml .github/workflows/release-trigger-staging.yml
54
+ name: Deploy to Trigger.dev (staging)
55
+
56
+ # Requires manually calling the workflow from a branch / commit to deploy to staging
57
+ on:
58
+ workflow_dispatch:
59
+
60
+ jobs:
61
+ deploy:
62
+ runs-on: ubuntu-latest
63
+
64
+ steps:
65
+ - uses: actions/checkout@v4
66
+
67
+ - name: Use Node.js 20.x
68
+ uses: actions/setup-node@v4
69
+ with:
70
+ node-version: "20.x"
71
+
72
+ - name: Install dependencies
73
+ run: npm install
74
+
75
+ - name: 🚀 Deploy Trigger.dev
76
+ env:
77
+ TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
78
+ run: |
79
+ npx trigger.dev@latest deploy --env staging
80
+ ```
81
+
82
+ </CodeGroup>
83
+
84
+ If you already have a GitHub action file, you can just add the final step "🚀 Deploy Trigger.dev" to your existing file.
85
+
86
+ ## Preview branches
87
+
88
+ To deploy to preview branches from Pull Requests and have them archived when PRs are merged or closed, use a workflow that runs on `pull_request` with **all four types** including `closed`:
89
+
90
+ ```yaml .github/workflows/trigger-preview-branches.yml
91
+ name: Deploy to Trigger.dev (preview branches)
92
+
93
+ on:
94
+ pull_request:
95
+ types: [opened, synchronize, reopened, closed]
96
+
97
+ jobs:
98
+ deploy-preview:
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - uses: actions/checkout@v4
102
+
103
+ - name: Use Node.js 20.x
104
+ uses: actions/setup-node@v4
105
+ with:
106
+ node-version: "20.x"
107
+
108
+ - name: Install dependencies
109
+ run: npm install
110
+
111
+ - name: Deploy preview branch
112
+ run: npx trigger.dev@latest deploy --env preview
113
+ env:
114
+ TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
115
+ ```
116
+
117
+ <Note>
118
+ **Include `closed`** in the `pull_request.types` list. Without it, preview branches won't be archived when PRs are merged or closed, and you may hit the limit on active preview branches. See [Preview branches](/deployment/preview-branches#preview-branches-with-github-actions-recommended) for more details.
119
+ </Note>
120
+
121
+ ## Creating a Personal Access Token
122
+
123
+ <Steps>
124
+
125
+ <Step title="Create a new access token">
126
+ Go to your profile page and click on the ["Personal Access
127
+ Tokens"](https://cloud.trigger.dev/account/tokens) tab.
128
+ </Step>
129
+
130
+ <Step title="Go to your repository on GitHub.">
131
+ Click on 'Settings' -> 'Secrets and variables' -> 'Actions' -> 'New repository secret'
132
+ </Step>
133
+
134
+ <Step title="Add the TRIGGER_ACCESS_TOKEN">
135
+ Add the name `TRIGGER_ACCESS_TOKEN` and the value of your access token. ![Add TRIGGER_ACCESS_TOKEN
136
+ in GitHub](/images/github-access-token.png)
137
+ </Step>
138
+
139
+ </Steps>
140
+
141
+ ## CLI Version pinning
142
+
143
+ The CLI and `@trigger.dev/*` package versions need to be in sync with the `trigger.dev` CLI, otherwise there will be errors and unpredictable behavior. Hence, the `deploy` command will automatically fail during CI on any version mismatches.
144
+ Tip: add the `trigger.dev` CLI to your `devDependencies` and the deploy command to your `package.json` file to keep versions managed in the same place. For example:
145
+
146
+ ```json
147
+ {
148
+ "scripts": {
149
+ "deploy:trigger-prod": "trigger deploy",
150
+ "deploy:trigger": "trigger deploy --env staging"
151
+ },
152
+ "devDependencies": {
153
+ "trigger.dev": "4.0.2"
154
+ }
155
+ }
156
+ ```
157
+
158
+ Your workflow file will follow the version specified in the `package.json` script, like so:
159
+
160
+ ```yaml .github/workflows/release-trigger.yml
161
+ - name: 🚀 Deploy Trigger.dev
162
+ env:
163
+ TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
164
+ run: |
165
+ npm run deploy:trigger
166
+ ```
167
+
168
+ You should use the version you run locally during dev and manual deploy. The current version is displayed in the banner, but you can also check it by appending `--version` to any command.
169
+
170
+ ## Self-hosting
171
+
172
+ When self-hosting, you need to:
173
+
174
+ - Set up Docker Buildx in your CI environment for building images locally.
175
+ - Add your registry credentials to the GitHub secrets.
176
+ - Specify the `TRIGGER_API_URL` environment variable pointing to your webapp domain, for example: `https://trigger.example.com`
177
+
178
+ <CodeGroup>
179
+
180
+ ```yaml .github/workflows/release-trigger-self-hosted.yml
181
+ name: Deploy to Trigger.dev (self-hosted)
182
+
183
+ on:
184
+ push:
185
+ branches:
186
+ - main
187
+
188
+ jobs:
189
+ deploy:
190
+ runs-on: ubuntu-latest
191
+
192
+ steps:
193
+ - uses: actions/checkout@v4
194
+
195
+ - name: Use Node.js 20.x
196
+ uses: actions/setup-node@v4
197
+ with:
198
+ node-version: "20.x"
199
+
200
+ - name: Install dependencies
201
+ run: npm install
202
+
203
+ - name: Set up Docker Buildx
204
+ uses: docker/setup-buildx-action@v3
205
+ with:
206
+ version: latest
207
+
208
+ - name: Login to DockerHub
209
+ uses: docker/login-action@v3
210
+ with:
211
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
212
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
213
+
214
+ - name: 🚀 Deploy Trigger.dev
215
+ env:
216
+ TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
217
+ TRIGGER_API_URL: ${{ secrets.TRIGGER_API_URL }}
218
+ run: |
219
+ npx trigger.dev@latest deploy
220
+ ```
221
+
222
+ </CodeGroup>