UNPKG

@convex-dev/action-retrier

Version:

Convex component for retrying idempotent actions.

103 lines (98 loc) 2.58 kB
import { mutation, query } from "./_generated/server.js"; import { v } from "convex/values"; import { options, runResult } from "./schema.js"; import { finishExecution, startRun } from "./run.js"; export const start = mutation({ args: { functionHandle: v.string(), functionArgs: v.any(), options, }, returns: v.string(), handler: async (ctx, args) => { return await startRun( ctx, args.functionHandle, args.functionArgs, args.options, ); }, }); export const status = query({ args: { runId: v.string(), }, returns: v.union( v.object({ type: v.literal("inProgress"), }), v.object({ type: v.literal("completed"), result: runResult, }), ), handler: async (ctx, args) => { const id = ctx.db.normalizeId("runs", args.runId); if (!id) { throw new Error(`Run ${args.runId} not found`); } const run = await ctx.db.get(id); if (!run) { throw new Error(`Run ${args.runId} not found`); } if (run.state.type === "inProgress") { return { type: "inProgress" as const }; } else if (run.state.type === "completed") { return { type: "completed" as const, result: run.state.result }; } else { throw new Error(`Invalid run state: ${JSON.stringify(run.state)}`); } }, }); export const cancel = mutation({ args: { runId: v.string(), }, returns: v.boolean(), handler: async (ctx, args) => { const id = ctx.db.normalizeId("runs", args.runId); if (!id) { return false; } const run = await ctx.db.get(id); if (!run) { return false; } if (run.state.type !== "inProgress") { return false; } const schedulerId = run.state.schedulerId; if (!schedulerId) { return false; } // Note that this doesn't terminate execution immediately, but // we are guaranteed that `finishExecution` won't succeed. await ctx.scheduler.cancel(schedulerId); await finishExecution(ctx, { runId: id, result: { type: "canceled" } }); return true; }, }); export const cleanup = mutation({ args: { runId: v.string(), }, handler: async (ctx, args) => { const id = ctx.db.normalizeId("runs", args.runId); if (!id) { throw new Error(`Run ${args.runId} not found`); } const run = await ctx.db.get(id); if (!run) { throw new Error(`Run ${args.runId} not found`); } if (run.state.type !== "completed") { throw new Error(`Run ${args.runId} hasn't completed.`); } await ctx.db.delete(id); }, });