Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c48b27a

Browse files
authored
Merge branch 'main' into wait-for-http-callback
2 parents 3f50577 + 053389d commit c48b27a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1484
-289
lines changed

.changeset/pre.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
"green-lions-relate",
2626
"hip-cups-wave",
2727
"honest-files-decide",
28+
"itchy-games-sort",
2829
"late-chairs-ring",
2930
"moody-squids-count",
3031
"nice-colts-boil",
3132
"polite-impalas-care",
3233
"polite-lies-fix",
34+
"real-rats-drop",
35+
"red-chairs-begin",
3336
"red-wasps-cover",
3437
"shiny-kiwis-beam",
3538
"smart-coins-hammer",
@@ -42,6 +45,7 @@
4245
"tricky-houses-invite",
4346
"two-tigers-dream",
4447
"weak-jobs-hide",
45-
"wet-deers-think"
48+
"wet-deers-think",
49+
"wet-steaks-reflect"
4650
]
4751
}

.changeset/real-rats-drop.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
---
4+
5+
Add onCancel lifecycle hook

.github/workflows/publish-worker-re2.yml renamed to .github/workflows/publish-worker-v4.yml

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: "⚒️ Publish Worker RE2"
1+
name: "⚒️ Publish Worker (v4)"
22

33
on:
44
workflow_call:
@@ -85,11 +85,11 @@ jobs:
8585
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
8686
IMAGE_TAG: ${{ steps.get_tag.outputs.tag }}
8787

88-
- name: 🐙 Push 'v3' tag to GitHub Container Registry
89-
if: steps.get_tag.outputs.is_semver == 'true'
90-
run: |
91-
docker tag infra_image "$REGISTRY/$REPOSITORY:v3"
92-
docker push "$REGISTRY/$REPOSITORY:v3"
93-
env:
94-
REGISTRY: ghcr.io/triggerdotdev
95-
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
88+
# - name: 🐙 Push 'v3' tag to GitHub Container Registry
89+
# if: steps.get_tag.outputs.is_semver == 'true'
90+
# run: |
91+
# docker tag infra_image "$REGISTRY/$REPOSITORY:v3"
92+
# docker push "$REGISTRY/$REPOSITORY:v3"
93+
# env:
94+
# REGISTRY: ghcr.io/triggerdotdev
95+
# REPOSITORY: ${{ steps.get_repository.outputs.repo }}

.github/workflows/publish-worker.yml

+8-8
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ jobs:
7777
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
7878
IMAGE_TAG: ${{ steps.get_tag.outputs.tag }}
7979

80-
- name: 🐙 Push 'v3' tag to GitHub Container Registry
81-
if: steps.get_tag.outputs.is_semver == 'true'
82-
run: |
83-
docker tag infra_image "$REGISTRY/$REPOSITORY:v3"
84-
docker push "$REGISTRY/$REPOSITORY:v3"
85-
env:
86-
REGISTRY: ghcr.io/triggerdotdev
87-
REPOSITORY: ${{ steps.get_repository.outputs.repo }}
80+
# - name: 🐙 Push 'v3' tag to GitHub Container Registry
81+
# if: steps.get_tag.outputs.is_semver == 'true'
82+
# run: |
83+
# docker tag infra_image "$REGISTRY/$REPOSITORY:v3"
84+
# docker push "$REGISTRY/$REPOSITORY:v3"
85+
# env:
86+
# REGISTRY: ghcr.io/triggerdotdev
87+
# REPOSITORY: ${{ steps.get_repository.outputs.repo }}

.github/workflows/publish.yml

+9-2
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,22 @@ jobs:
5656
secrets: inherit
5757

5858
publish-webapp:
59-
needs: [typecheck]
59+
needs: [typecheck, units]
6060
uses: ./.github/workflows/publish-webapp.yml
6161
secrets: inherit
6262
with:
6363
image_tag: ${{ inputs.image_tag }}
6464

6565
publish-worker:
66-
needs: [typecheck]
66+
needs: [typecheck, units]
6767
uses: ./.github/workflows/publish-worker.yml
6868
secrets: inherit
6969
with:
7070
image_tag: ${{ inputs.image_tag }}
71+
72+
publish-worker-v4:
73+
needs: [typecheck, units]
74+
uses: ./.github/workflows/publish-worker-v4.yml
75+
secrets: inherit
76+
with:
77+
image_tag: ${{ inputs.image_tag }}

.github/workflows/unit-tests.yml

+26
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,32 @@ jobs:
88
name: "🧪 Unit Tests"
99
runs-on: ubuntu-latest
1010
steps:
11+
- name: 🔧 Disable IPv6
12+
run: |
13+
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
14+
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
15+
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1
16+
17+
- name: 🔧 Configure docker address pool
18+
run: |
19+
CONFIG='{
20+
"default-address-pools" : [
21+
{
22+
"base" : "172.17.0.0/12",
23+
"size" : 20
24+
},
25+
{
26+
"base" : "192.168.0.0/16",
27+
"size" : 24
28+
}
29+
]
30+
}'
31+
mkdir -p /etc/docker
32+
echo "$CONFIG" | sudo tee /etc/docker/daemon.json
33+
34+
- name: 🔧 Restart docker daemon
35+
run: sudo systemctl restart docker
36+
1137
- name: ⬇️ Checkout repo
1238
uses: actions/checkout@v4
1339
with:

apps/webapp/app/components/runs/v3/RunIcon.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export function RunIcon({ name, className, spanName }: TaskIconProps) {
9797
case "task-hook-onResume":
9898
case "task-hook-onComplete":
9999
case "task-hook-cleanup":
100+
case "task-hook-onCancel":
100101
return <FunctionIcon className={cn(className, "text-text-dimmed")} />;
101102
case "task-hook-onFailure":
102103
case "task-hook-catchError":

apps/webapp/app/env.server.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ const EnvironmentSchema = z.object({
460460
RUN_ENGINE_REUSE_SNAPSHOT_COUNT: z.coerce.number().int().default(0),
461461
RUN_ENGINE_MAXIMUM_ENV_COUNT: z.coerce.number().int().optional(),
462462
RUN_ENGINE_WORKER_SHUTDOWN_TIMEOUT_MS: z.coerce.number().int().default(60_000),
463+
RUN_ENGINE_RETRY_WARM_START_THRESHOLD_MS: z.coerce.number().int().default(30_000),
463464

464465
RUN_ENGINE_WORKER_REDIS_HOST: z
465466
.string()
@@ -717,7 +718,7 @@ const EnvironmentSchema = z.object({
717718

718719
SLACK_BOT_TOKEN: z.string().optional(),
719720
SLACK_SIGNUP_REASON_CHANNEL_ID: z.string().optional(),
720-
721+
721722
// kapa.ai
722723
KAPA_AI_WEBSITE_ID: z.string().optional(),
723724
});

apps/webapp/app/runEngine/validators/triggerTaskValidator.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class DefaultTriggerTaskValidator implements TriggerTaskValidator {
4646

4747
const result = await getEntitlement(environment.organizationId);
4848

49-
if (!result || result.hasAccess === false) {
49+
if (result && result.hasAccess === false) {
5050
return {
5151
ok: false,
5252
error: new OutOfEntitlementError(),

apps/webapp/app/v3/runEngine.server.ts

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ function createRunEngine() {
9595
...(env.RUN_ENGINE_RUN_QUEUE_REDIS_TLS_DISABLED === "true" ? {} : { tls: {} }),
9696
},
9797
},
98+
retryWarmStartThresholdMs: env.RUN_ENGINE_RETRY_WARM_START_THRESHOLD_MS,
9899
});
99100

100101
return engine;

apps/webapp/app/v3/services/cancelTaskRun.server.ts

-23
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,6 @@ export class CancelTaskRunService extends BaseService {
4747
tx: this._prisma,
4848
});
4949

50-
const inProgressEvents = await eventRepository.queryIncompleteEvents(
51-
getTaskEventStoreTableForRun(taskRun),
52-
{
53-
runId: taskRun.friendlyId,
54-
},
55-
taskRun.createdAt,
56-
taskRun.completedAt ?? undefined
57-
);
58-
59-
logger.debug("Cancelling in-progress events", {
60-
inProgressEvents: inProgressEvents.map((event) => event.id),
61-
});
62-
63-
await Promise.all(
64-
inProgressEvents.map((event) => {
65-
return eventRepository.cancelEvent(
66-
event,
67-
options?.cancelledAt ?? new Date(),
68-
options?.reason ?? "Run cancelled"
69-
);
70-
})
71-
);
72-
7350
return {
7451
id: result.run.id,
7552
};

apps/webapp/tsconfig.check.json

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{
22
"extends": "./tsconfig.json",
33
"compilerOptions": {
4+
"lib": ["DOM", "DOM.Iterable", "DOM.AsyncIterable", "ES2022"],
5+
"target": "ES2022",
46
"noEmit": true,
57
"paths": {
68
"~/*": ["./app/*"],

docs/upgrade-to-v4.mdx

+103-2
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,107 @@ tasks.onComplete(({ ctx, result }) => {
170170
});
171171
```
172172

173+
### onCancel
174+
175+
<Note>Available in v4.0.0-beta.12 and later.</Note>
176+
177+
You can now define an `onCancel` hook that is called when a run is cancelled. This is useful if you want to clean up any resources that were allocated for the run.
178+
179+
```ts
180+
tasks.onCancel(({ ctx, signal }) => {
181+
console.log("Run cancelled", signal);
182+
});
183+
```
184+
185+
You can use the `onCancel` hook along with the `signal` passed into the run function to interrupt a call to an external service, for example using the [streamText](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) function from the AI SDK:
186+
187+
```ts
188+
import { logger, tasks, schemaTask } from "@trigger.dev/sdk";
189+
import { streamText } from "ai";
190+
import { z } from "zod";
191+
192+
export const interruptibleChat = schemaTask({
193+
id: "interruptible-chat",
194+
description: "Chat with the AI",
195+
schema: z.object({
196+
prompt: z.string().describe("The prompt to chat with the AI"),
197+
}),
198+
run: async ({ prompt }, { signal }) => {
199+
const chunks: TextStreamPart<{}>[] = [];
200+
201+
// 👇 This is a global onCancel hook, but it's inside of the run function
202+
tasks.onCancel(async () => {
203+
// We have access to the chunks here, and can save them to the database
204+
await saveChunksToDatabase(chunks);
205+
});
206+
207+
try {
208+
const result = streamText({
209+
model: getModel(),
210+
prompt,
211+
experimental_telemetry: {
212+
isEnabled: true,
213+
},
214+
tools: {},
215+
abortSignal: signal, // 👈 Pass the signal to the streamText function, which aborts with the run is cancelled
216+
onChunk: ({ chunk }) => {
217+
chunks.push(chunk);
218+
},
219+
});
220+
221+
const textParts = [];
222+
223+
for await (const part of result.textStream) {
224+
textParts.push(part);
225+
}
226+
227+
return textParts.join("");
228+
} catch (error) {
229+
if (error instanceof Error && error.name === "AbortError") {
230+
// streamText will throw an AbortError if the signal is aborted, so we can handle it here
231+
} else {
232+
throw error;
233+
}
234+
}
235+
},
236+
});
237+
```
238+
239+
The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run:
240+
241+
```ts
242+
import { logger, task } from "@trigger.dev/sdk";
243+
import { setTimeout } from "node:timers/promises";
244+
245+
export const cancelExampleTask = task({
246+
id: "cancel-example",
247+
// Signal will be aborted when the task is cancelled 👇
248+
run: async (payload: { message: string }, { signal }) => {
249+
try {
250+
// We pass the signal to setTimeout to abort the timeout if the task is cancelled
251+
await setTimeout(10_000, undefined, { signal });
252+
} catch (error) {
253+
// Ignore the abort error
254+
}
255+
256+
// Do some more work here
257+
258+
return {
259+
message: "Hello, world!",
260+
};
261+
},
262+
onCancel: async ({ runPromise }) => {
263+
// You can await the runPromise to get the output of the task
264+
const output = await runPromise;
265+
},
266+
});
267+
```
268+
269+
<Note>
270+
You will have up to 30 seconds to complete the `runPromise` in the `onCancel` hook. After that
271+
point the process will be killed.
272+
</Note>
273+
173274
### Improved middleware and locals
174275

175276
Our task middleware system is now much more useful. Previously it only ran "around" the `run` function, but now we've hoisted it to the top level and it now runs before/after all the other hooks.
@@ -704,7 +805,7 @@ export const myTask = task({
704805
id: "my-task",
705806
onStart: ({ payload, ctx }) => {},
706807
// The run function still uses separate parameters
707-
run: async ( payload, { ctx }) => {},
808+
run: async (payload, { ctx }) => {},
708809
});
709810
```
710811

@@ -760,4 +861,4 @@ const batchHandle = await tasks.batchTrigger([
760861
// Now you need to call runs.list()
761862
const runs = await batchHandle.runs.list();
762863
console.log(runs);
763-
```
864+
```

internal-packages/run-engine/src/engine/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ export class RunEngine {
304304
waitpointSystem: this.waitpointSystem,
305305
delayedRunSystem: this.delayedRunSystem,
306306
machines: this.options.machines,
307+
retryWarmStartThresholdMs: this.options.retryWarmStartThresholdMs,
307308
});
308309

309310
this.dequeueSystem = new DequeueSystem({

0 commit comments

Comments
 (0)