@convex-dev/workpool
Version:
A Convex component for managing async work.
426 lines • 19.3 kB
TypeScript
import { DefaultFunctionArgs, FunctionReference, FunctionType, FunctionVisibility, GenericDataModel, GenericMutationCtx, RegisteredMutation } from "convex/server";
import { Infer, Validator, VAny, VString } from "convex/values";
import { Mounts } from "../component/_generated/api.js";
import { type LogLevel } from "../component/logging.js";
import { vResultValidator, type RetryBehavior, RunResult, Status } from "../component/shared.js";
import { RunMutationCtx, RunQueryCtx, UseApi } from "./utils.js";
export { vResultValidator, type RunResult, type RetryBehavior };
export { retryBehavior as vRetryBehavior } from "../component/shared.js";
export { logLevel as vLogLevel, type LogLevel } from "../component/logging.js";
export type WorkId = string & {
__isWorkId: true;
};
export declare const vWorkIdValidator: VString<WorkId>;
export {
/** @deprecated Use `vWorkIdValidator` instead. */
vWorkIdValidator as workIdValidator,
/** @deprecated Use `vResultValidator` instead. */
vResultValidator as resultValidator, };
/** Equivalent to `vOnCompleteArgs(<your-context-validator>)`. */
export declare const vOnComplete: import("convex/values").VObject<{
context: any;
workId: WorkId;
result: {
kind: "success";
returnValue: any;
} | {
kind: "failed";
error: string;
} | {
kind: "canceled";
};
}, {
workId: VString<WorkId, "required">;
context: VAny<any, "required", string>;
result: import("convex/values").VUnion<{
kind: "success";
returnValue: any;
} | {
kind: "failed";
error: string;
} | {
kind: "canceled";
}, [import("convex/values").VObject<{
kind: "success";
returnValue: any;
}, {
kind: import("convex/values").VLiteral<"success", "required">;
returnValue: VAny<any, "required", string>;
}, "required", "kind" | "returnValue" | `returnValue.${string}`>, import("convex/values").VObject<{
kind: "failed";
error: string;
}, {
kind: import("convex/values").VLiteral<"failed", "required">;
error: VString<string, "required">;
}, "required", "kind" | "error">, import("convex/values").VObject<{
kind: "canceled";
}, {
kind: import("convex/values").VLiteral<"canceled", "required">;
}, "required", "kind">], "required", "kind" | "returnValue" | `returnValue.${string}` | "error">;
}, "required", "context" | `context.${string}` | "workId" | "result" | "result.kind" | "result.returnValue" | `result.returnValue.${string}` | "result.error">;
/** @deprecated Use `vOnCompleteArgs()` instead. */
export declare const vOnCompleteValidator: typeof vOnCompleteArgs;
export declare const DEFAULT_RETRY_BEHAVIOR: RetryBehavior;
export type WorkpoolComponent = UseApi<Mounts>;
export declare class Workpool {
component: WorkpoolComponent;
options: WorkpoolOptions;
/**
* Initializes a Workpool.
*
* Note: if you want different pools, you need to *create different instances*
* of Workpool in convex.config.ts. It isn't sufficient to have different
* instances of this class.
*
* @param component - The component to use, like `components.workpool` from
* `./_generated/api.ts`.
* @param options - The {@link WorkpoolOptions} for the Workpool.
*/
constructor(component: WorkpoolComponent, options: WorkpoolOptions);
/**
* Enqueues an action to be run.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param fn - The action to run, like `internal.example.myAction`.
* @param fnArgs - The arguments to pass to the action.
* @param options - The options for the action to specify retry behavior,
* onComplete handling, and scheduling via `runAt` or `runAfter`.
* @returns The ID of the work that was enqueued.
*/
enqueueAction<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"action", FunctionVisibility, Args, ReturnType>, fnArgs: Args, options?: RetryOption & EnqueueOptions): Promise<WorkId>;
/**
* Enqueues a batch of actions to be run.
* Each action will be run independently, and the onComplete handler will
* be called for each action.
*
* @param ctx - The mutation or action ctx that can call ctx.runMutation.
* @param fn - The action to run, like `internal.example.myAction`.
* @param argsArray - The arguments to pass to the action.
* @param options - The options for the actions to specify retry behavior,
* onComplete handling, and scheduling via `runAt` or `runAfter`.
* @returns The IDs of the work that was enqueued.
*/
enqueueActionBatch<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"action", FunctionVisibility, Args, ReturnType>, argsArray: Array<Args>, options?: RetryOption & EnqueueOptions): Promise<WorkId[]>;
/**
* Enqueues a mutation to be run.
*
* Note: mutations are not retried by the workpool. Convex automatically
* retries them on database conflicts and transient failures.
* Because they're deterministic, external retries don't provide any benefit.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param fn - The mutation to run, like `internal.example.myMutation`.
* @param fnArgs - The arguments to pass to the mutation.
* @param options - The options for the mutation to specify onComplete handling
* and scheduling via `runAt` or `runAfter`.
*/
enqueueMutation<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"mutation", FunctionVisibility, Args, ReturnType>, fnArgs: Args, options?: EnqueueOptions): Promise<WorkId>;
/**
* Enqueues a batch of mutations to be run.
* Each mutation will be run independently, and the onComplete handler will
* be called for each mutation.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param fn - The mutation to run, like `internal.example.myMutation`.
* @param argsArray - The arguments to pass to the mutations.
* @param options - The options for the mutations to specify onComplete handling
* and scheduling via `runAt` or `runAfter`.
*/
enqueueMutationBatch<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"mutation", FunctionVisibility, Args, ReturnType>, argsArray: Array<Args>, options?: EnqueueOptions): Promise<WorkId[]>;
/**
* Enqueues a query to be run.
* Usually not what you want, but it can be useful during workflows.
* The query is run in a mutation and the result is returned to the caller,
* so it can conflict if other mutations are writing the value.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param fn - The query to run, like `internal.example.myQuery`.
* @param fnArgs - The arguments to pass to the query.
* @param options - The options for the query to specify onComplete handling
* and scheduling via `runAt` or `runAfter`.
*/
enqueueQuery<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"query", FunctionVisibility, Args, ReturnType>, fnArgs: Args, options?: EnqueueOptions): Promise<WorkId>;
/**
* Enqueues a batch of queries to be run.
* Each query will be run independently, and the onComplete handler will
* be called for each query.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param fn - The query to run, like `internal.example.myQuery`.
* @param argsArray - The arguments to pass to the queries.
* @param options - The options for the queries to specify onComplete handling
* and scheduling via `runAt` or `runAfter`.
*/
enqueueQueryBatch<Args extends DefaultFunctionArgs, ReturnType>(ctx: RunMutationCtx, fn: FunctionReference<"query", FunctionVisibility, Args, ReturnType>, argsArray: Array<Args>, options?: EnqueueOptions): Promise<WorkId[]>;
/**
* Cancels a work item. If it's already started, it will be allowed to finish
* but will not be retried.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
* @param id - The ID of the work to cancel.
*/
cancel(ctx: RunMutationCtx, id: WorkId): Promise<void>;
/**
* Cancels all pending work items. See {@link cancel}.
*
* @param ctx - The mutation or action context that can call ctx.runMutation.
*/
cancelAll(ctx: RunMutationCtx): Promise<void>;
/**
* Gets the status of a work item.
*
* @param ctx - The query context that can call ctx.runQuery.
* @param id - The ID of the work to get the status of.
* @returns The status of the work item. One of:
* - `{ state: "pending", previousAttempts: number }`
* - `{ state: "running", previousAttempts: number }`
* - `{ state: "finished" }`
*/
status(ctx: RunQueryCtx, id: WorkId): Promise<Status>;
/**
* Gets the status of a batch of work items.
*
* @param ctx - The query context that can call ctx.runQuery.
* @param ids - The IDs of the work to get the status of.
* @returns The status of the work items.
*/
statusBatch(ctx: RunQueryCtx, ids: WorkId[]): Promise<Status[]>;
/**
* Defines a mutation that will be run after a work item completes.
* You can pass this to a call to enqueue* like so:
* ```ts
* export const myOnComplete = workpool.defineOnComplete({
* context: v.literal("myContextValue"), // optional
* handler: async (ctx, {workId, context, result}) => {
* // ... do something with the result
* },
* });
*
* // in some other function:
* const workId = await workpool.enqueueAction(ctx, internal.foo.bar, {
* // ... args to action
* }, {
* onComplete: internal.foo.myOnComplete,
* });
* ```
*/
defineOnComplete<DataModel extends GenericDataModel, V extends Validator<any, any, any> = VAny<any, "optional">>({ context, handler, }: {
context?: V;
handler: (ctx: GenericMutationCtx<DataModel>, args: {
workId: WorkId;
context: Infer<V>;
result: RunResult;
}) => Promise<void>;
}): RegisteredMutation<"internal", OnCompleteArgs, null>;
}
/**
* Returns a validator to use for the onComplete mutation.
* To be used like:
* ```ts
* export const myOnComplete = internalMutation({
* args: vOnCompleteArgs(v.string()),
* handler: async (ctx, {workId, context, result}) => {
* // context has been validated as a string
* // ... do something with the result
* },
* });
* @param context - The context validator. If not provided, it will be `v.any()`.
* @returns The validator for the onComplete mutation.
*/
export declare function vOnCompleteArgs<V extends Validator<any, "required", any> = VAny>(context?: V): import("convex/values").VObject<import("convex/server").Expand<{ [Property in V["isOptional"] extends "optional" ? "context" : never]?: Exclude<Infer<{
workId: VString<WorkId, "required">;
context: V;
result: import("convex/values").VUnion<{
kind: "success";
returnValue: any;
} | {
kind: "failed";
error: string;
} | {
kind: "canceled";
}, [import("convex/values").VObject<{
kind: "success";
returnValue: any;
}, {
kind: import("convex/values").VLiteral<"success", "required">;
returnValue: VAny<any, "required", string>;
}, "required", "kind" | "returnValue" | `returnValue.${string}`>, import("convex/values").VObject<{
kind: "failed";
error: string;
}, {
kind: import("convex/values").VLiteral<"failed", "required">;
error: VString<string, "required">;
}, "required", "kind" | "error">, import("convex/values").VObject<{
kind: "canceled";
}, {
kind: import("convex/values").VLiteral<"canceled", "required">;
}, "required", "kind">], "required", "kind" | "returnValue" | `returnValue.${string}` | "error">;
}[Property]>, undefined> | undefined; } & { [Property_1 in Exclude<"context", V["isOptional"] extends "optional" ? "context" : never> | Exclude<"workId", V["isOptional"] extends "optional" ? "context" : never> | Exclude<"result", V["isOptional"] extends "optional" ? "context" : never>]: Infer<{
workId: VString<WorkId, "required">;
context: V;
result: import("convex/values").VUnion<{
kind: "success";
returnValue: any;
} | {
kind: "failed";
error: string;
} | {
kind: "canceled";
}, [import("convex/values").VObject<{
kind: "success";
returnValue: any;
}, {
kind: import("convex/values").VLiteral<"success", "required">;
returnValue: VAny<any, "required", string>;
}, "required", "kind" | "returnValue" | `returnValue.${string}`>, import("convex/values").VObject<{
kind: "failed";
error: string;
}, {
kind: import("convex/values").VLiteral<"failed", "required">;
error: VString<string, "required">;
}, "required", "kind" | "error">, import("convex/values").VObject<{
kind: "canceled";
}, {
kind: import("convex/values").VLiteral<"canceled", "required">;
}, "required", "kind">], "required", "kind" | "returnValue" | `returnValue.${string}` | "error">;
}[Property_1]>; }>, {
workId: VString<WorkId, "required">;
context: V;
result: import("convex/values").VUnion<{
kind: "success";
returnValue: any;
} | {
kind: "failed";
error: string;
} | {
kind: "canceled";
}, [import("convex/values").VObject<{
kind: "success";
returnValue: any;
}, {
kind: import("convex/values").VLiteral<"success", "required">;
returnValue: VAny<any, "required", string>;
}, "required", "kind" | "returnValue" | `returnValue.${string}`>, import("convex/values").VObject<{
kind: "failed";
error: string;
}, {
kind: import("convex/values").VLiteral<"failed", "required">;
error: VString<string, "required">;
}, "required", "kind" | "error">, import("convex/values").VObject<{
kind: "canceled";
}, {
kind: import("convex/values").VLiteral<"canceled", "required">;
}, "required", "kind">], "required", "kind" | "returnValue" | `returnValue.${string}` | "error">;
}, "required", "context" | "workId" | "result" | `context.${V["fieldPaths"]}` | "result.kind" | "result.returnValue" | `result.returnValue.${string}` | "result.error">;
export type RetryOption = {
/** Whether to retry the action if it fails.
* If true, it will use the default retry behavior.
* If custom behavior is provided, it will retry using that behavior.
* If unset, it will use the Workpool's configured default.
*/
retry?: boolean | RetryBehavior;
};
export type WorkpoolOptions = {
/** How many actions/mutations can be running at once within this pool.
* Min 1, Suggested max: 100 on Pro, 20 on the free plan.
*/
maxParallelism?: number;
/** How much to log. This is updated on each call to `enqueue*`,
* `status`, or `cancel*`.
* Default is REPORT, which logs warnings, errors, and a periodic report.
* With INFO, you can also see events for started and completed work.
* Stats generated can be parsed by tools like
* [Axiom](https://axiom.co) for monitoring.
* With DEBUG, you can see timers and internal events for work being
* scheduled.
*/
logLevel?: LogLevel;
} & WorkpoolRetryOptions;
export type WorkpoolRetryOptions = {
/** Default retry behavior for enqueued actions.
* See {@link RetryBehavior}.
*/
defaultRetryBehavior?: RetryBehavior;
/** Whether to retry actions that fail by default. Default: false.
* NOTE: Only enable this if your actions are idempotent.
* See the docs (README.md) for more details.
*/
retryActionsByDefault?: boolean;
};
export type EnqueueOptions = {
/**
* The name of the function. By default, if you pass in api.foo.bar.baz,
* it will use "foo/bar:baz" as the name. If you pass in a function handle,
* it will use the function handle directly.
*/
name?: string;
/**
* A mutation to run after the function succeeds, fails, or is canceled.
* The context type is for your use, feel free to provide a validator for it.
* e.g.
* ```ts
* export const completion = workpool.defineOnComplete({
* context: v.string(),
* handler: async (ctx, {workId, context, result}) => {
* // context has been validated as a string
* // ... do something with the result
* },
* });
* ```
* or more manually:
* ```ts
* export const completion = internalMutation({
* args: vOnCompleteArgs(v.string()),
* handler: async (ctx, args) => {
* console.log(args.result, "Got Context back -> ", args.context, Date.now() - args.context);
* },
* });
* ```
*/
onComplete?: FunctionReference<"mutation", FunctionVisibility, OnCompleteArgs> | null;
/**
* A context object to pass to the `onComplete` mutation.
* Useful for passing data from the enqueue site to the onComplete site.
*/
context?: unknown;
} & ({
/**
* The time (ms since epoch) to run the action at.
* If not provided, the action will be run as soon as possible.
* Note: this is advisory only. It may run later.
*/
runAt?: number;
} | {
/**
* The number of milliseconds to run the action after.
* If not provided, the action will be run as soon as possible.
* Note: this is advisory only. It may run later.
*/
runAfter?: number;
});
export type OnCompleteArgs = {
/**
* The ID of the work that completed.
*/
workId: WorkId;
/**
* The context object passed when enqueuing the work.
* Useful for passing data from the enqueue site to the onComplete site.
*/
context: unknown;
/**
* The result of the run that completed.
*/
result: RunResult;
};
export declare function enqueueBatch<FnType extends FunctionType, Args extends DefaultFunctionArgs, ReturnType>(component: UseApi<Mounts>, ctx: RunMutationCtx, fnType: FnType, fn: FunctionReference<FnType, FunctionVisibility, Args, ReturnType>, fnArgsArray: Array<Args>, options: EnqueueOptions & {
retryBehavior?: RetryBehavior;
maxParallelism?: number;
logLevel?: LogLevel;
}): Promise<WorkId[]>;
export declare function enqueue<FnType extends FunctionType, Args extends DefaultFunctionArgs, ReturnType>(component: UseApi<Mounts>, ctx: RunMutationCtx, fnType: FnType, fn: FunctionReference<FnType, FunctionVisibility, Args, ReturnType>, fnArgs: Args, options: EnqueueOptions & {
retryBehavior?: RetryBehavior;
maxParallelism?: number;
logLevel?: LogLevel;
}): Promise<WorkId>;
//# sourceMappingURL=index.d.ts.map