diff --git a/packages/core/src/v3/schemas/messages.ts b/packages/core/src/v3/schemas/messages.ts index ed5358c59..2cb724d43 100644 --- a/packages/core/src/v3/schemas/messages.ts +++ b/packages/core/src/v3/schemas/messages.ts @@ -157,10 +157,21 @@ export const RateLimitOptions = z.discriminatedUnion("type", [ ]); export const RetryOptions = z.object({ + /** The number of attempts before giving up */ maxAttempts: z.number().int().optional(), + /** The exponential factor to use when calculating the next retry time. + * + * Each subsequent retry will be calculated as `previousTimeout * factor` + */ factor: z.number().optional(), + /** The minimum time to wait before retrying */ minTimeoutInMs: z.number().int().optional(), + /** The maximum time to wait before retrying */ maxTimeoutInMs: z.number().int().optional(), + /** Randomize the timeout between retries. + * + * This can be useful to prevent the thundering herd problem where all retries happen at the same time. + */ randomize: z.boolean().optional(), }); @@ -169,10 +180,44 @@ export type RetryOptions = z.infer; export type RateLimitOptions = z.infer; export const QueueOptions = z.object({ + /** You can define a shared queue and then pass the name in to your task. + * + * @example + * + * ```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 }) => { + // ... + }, + }); + * ``` + */ + name: z.string().optional(), + /** An optional property that specifies the maximum number of concurrent run executions. + * + * If this property is omitted, the task can potentially use up the full concurrency of an environment. */ + concurrencyLimit: z.number().int().min(1).max(1000).optional(), /** @deprecated This feature is coming soon */ rateLimit: RateLimitOptions.optional(), - concurrencyLimit: z.number().int().min(1).max(1000).optional(), - name: z.string().optional(), }); export type QueueOptions = z.infer; diff --git a/packages/core/src/v3/types/index.ts b/packages/core/src/v3/types/index.ts index 80a2bad86..071742dd9 100644 --- a/packages/core/src/v3/types/index.ts +++ b/packages/core/src/v3/types/index.ts @@ -7,7 +7,9 @@ export * from "./config"; export type InitOutput = Record | void | undefined; export type RunFnParams = Prettify<{ + /** Metadata about the task, run, attempt, queue, environment, organization, project and batch. */ ctx: Context; + /** If you use the `init` function, this will be whatever you returned. */ init?: TInitOutput; }>; diff --git a/packages/trigger-sdk/src/v3/shared.ts b/packages/trigger-sdk/src/v3/shared.ts index e87c5369f..188317668 100644 --- a/packages/trigger-sdk/src/v3/shared.ts +++ b/packages/trigger-sdk/src/v3/shared.ts @@ -38,13 +38,94 @@ export function queue(options: { name: string } & QueueOptions): Queue { } export type TaskOptions = { + /** An id for your task. This must be unique inside your project and not change between versions. */ id: string; + /** The retry settings when an uncaught error is thrown. + * + * If omitted it will use the values in your `trigger.config.ts` file. + * + * @example + * + * ``` + * 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 }) => { + //... + }, + }); + * ``` + * */ retry?: RetryOptions; + /** Used to configure what should happen when more than one run is triggered at the same time. + * + * @example + * one at a time execution + * + * ```ts + * export const oneAtATime = task({ + id: "one-at-a-time", + queue: { + concurrencyLimit: 1, + }, + run: async ({ payload, ctx }) => { + //... + }, + }); + * ``` + */ queue?: QueueOptions; + /** Configure the spec of the machine you want your task to run on. + * + * @example + * + * ```ts + * export const heavyTask = task({ + id: "heavy-task", + machine: { + cpu: 2, + memory: 4, + }, + run: async ({ payload, ctx }) => { + //... + }, + }); + * ``` + */ machine?: { - cpu?: number; - memory?: number; + /** vCPUs. The default is 0.5. + * + * Possible values: + * - 0.25 + * - 0.5 + * - 1 + * - 2 + * - 4 + */ + cpu?: 0.25 | 0.5 | 1 | 2 | 4; + /** In GBs of RAM. The default is 0.5. + * + * Possible values: + * - 0.25 + * - 0.5 + * - 1 + * - 2 + * - 4 + * - 8 + */ + memory?: 0.25 | 0.5 | 1 | 2 | 4 | 8; }; + /** This gets called when a task is triggered. It's where you put the code you want to execute. + * + * @param payload - The payload that is passed to your task when it's triggered. This must be JSON serializable. + * @param params - Metadata about the run. + */ run: (payload: TPayload, params: RunFnParams) => Promise; init?: (payload: TPayload, params: InitFnParams) => Promise; handleError?: ( diff --git a/packages/trigger-sdk/src/v3/tasks.ts b/packages/trigger-sdk/src/v3/tasks.ts index 0c9a2ad9f..274511f23 100644 --- a/packages/trigger-sdk/src/v3/tasks.ts +++ b/packages/trigger-sdk/src/v3/tasks.ts @@ -1,6 +1,24 @@ import { InitOutput } from "@trigger.dev/core/v3"; import { TaskOptions, Task, createTask } from "./shared"; +/** Creates a task that can be triggered + * @param options - Task options + * @example + * + * ```ts + * import { task } from "@trigger.dev/sdk/v3"; + * + * export const helloWorld = task({ + id: "hello-world", + * run: async (payload: { url: string }) => { + * return { hello: "world" }; + * }, + * }); + * + * ``` + * + * @returns A task that can be triggered + */ export function task( options: TaskOptions ): Task {