Skip to content

Very short waits count towards compute usage #1888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/snippets/paused-execution-free.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +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>
In the Trigger.dev Cloud we automatically pause execution of tasks when they are waiting for
longer than a few seconds.

When triggering and waiting for subtasks, the parent is checkpointed and while waiting does not count towards compute usage. When waiting for a time period (`wait.for` or `wait.until`), if the wait is longer than 5 seconds we checkpoint and it does not count towards compute usage.
78 changes: 78 additions & 0 deletions packages/trigger-sdk/src/v3/wait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,14 @@ export class WaitpointTimeoutError extends Error {
}
}

const DURATION_WAIT_CHARGE_THRESHOLD_MS = 5000;

function printWaitBelowThreshold() {
console.warn(
`Waits of ${DURATION_WAIT_CHARGE_THRESHOLD_MS / 1000}s or less count towards compute usage.`
);
}

export const wait = {
for: async (options: WaitForOptions) => {
const ctx = taskContext.ctx;
Expand All @@ -380,6 +388,36 @@ export const wait = {

const start = Date.now();
const durationInMs = calculateDurationInMs(options);

if (durationInMs <= DURATION_WAIT_CHARGE_THRESHOLD_MS) {
return tracer.startActiveSpan(
`wait.for()`,
async (span) => {
if (durationInMs <= 0) {
return;
}

printWaitBelowThreshold();

await new Promise((resolve) => setTimeout(resolve, durationInMs));
},
{
attributes: {
[SemanticInternalAttributes.STYLE_ICON]: "wait",
...accessoryAttributes({
items: [
{
text: nameForWaitOptions(options),
variant: "normal",
},
],
style: "codepath",
}),
},
}
);
}

const date = new Date(start + durationInMs);
const result = await apiClient.waitForDuration(ctx.run.id, {
date: date,
Expand Down Expand Up @@ -417,6 +455,46 @@ export const wait = {
throw new Error("wait.forToken can only be used from inside a task.run()");
}

// Calculate duration in ms
const durationInMs = options.date.getTime() - Date.now();

if (durationInMs <= DURATION_WAIT_CHARGE_THRESHOLD_MS) {
return tracer.startActiveSpan(
`wait.for()`,
async (span) => {
if (durationInMs === 0) {
return;
}

if (durationInMs < 0) {
if (options.throwIfInThePast) {
throw new Error("Date is in the past");
}

return;
}

printWaitBelowThreshold();

await new Promise((resolve) => setTimeout(resolve, durationInMs));
},
{
attributes: {
[SemanticInternalAttributes.STYLE_ICON]: "wait",
...accessoryAttributes({
items: [
{
text: options.date.toISOString(),
variant: "normal",
},
],
style: "codepath",
}),
},
}
);
}

const apiClient = apiClientManager.clientOrThrow();

const result = await apiClient.waitForDuration(ctx.run.id, {
Expand Down