### Install Dependencies and Run Locally Source: https://github.com/get-convex/action-retrier/blob/main/CONTRIBUTING.md Installs project dependencies and starts the development server. ```sh npm i npm run dev ``` -------------------------------- ### Manual Start Mutation Example Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/04-public-mutations-and-queries.md Demonstrates how to manually start a run using `ctx.runMutation`. This is not recommended for general use as the `ActionRetrier` class handles serialization and type-safety. ```typescript import { internal, components } from "./_generated/api"; import { mutation } from "./_generated/server"; export const manualStart = mutation({ args: { /* your args */ }, handler: async (ctx, args) => { // Start a run manually (not recommended) const runId = await ctx.runMutation(components.actionRetrier.public.start, { functionHandle: "...", // serialized handle functionArgs: { /* ... */ }, options: { initialBackoffMs: 250, base: 2, maxFailures: 4, logLevel: "INFO", }, }); return runId; }, }); ``` -------------------------------- ### Complete Action Retrier Setup Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/03-validators.md Demonstrates a full setup for the Action Retrier, including defining the action to retry, a completion handler, and mutations to start and check the status of a run. Ensure necessary imports are present. ```typescript // src/index.ts import { ActionRetrier, runIdValidator, onCompleteValidator } from "@convex-dev/action-retrier"; import { components } from "./_generated/api"; import { internalAction, internalMutation, mutation } from "./_generated/server"; import { v } from "convex/values"; const retrier = new ActionRetrier(components.actionRetrier); // The action to retry export const externalCall = internalAction({ args: { url: v.string() }, handler: async (ctx, args) => { const response = await fetch(args.url); return response.json(); }, }); // Completion handler export const handleCompletion = internalMutation({ args: onCompleteValidator, handler: async (ctx, args) => { if (args.result.type === "success") { console.log("Completed:", args.result.returnValue); } }, }); // Mutation to start the run export const startRun = mutation({ args: { url: v.string() }, handler: async (ctx, args) => { return await retrier.run(ctx, internal.index.externalCall, { url: args.url }, { onComplete: internal.index.handleCompletion, }); }, }); // Query to check status export const checkRun = mutation({ args: { runId: runIdValidator }, handler: async (ctx, args) => { return await retrier.status(ctx, args.runId); }, }); ``` -------------------------------- ### Run Convex Development Server Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Execute this command to start the Convex development server and check for installation errors. ```bash npx convex dev ``` -------------------------------- ### Start Convex Dev Server Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Use this command to start the Convex development server for local development. ```bash # Start Convex dev server npx convex dev # In another terminal, start your application npm run dev ``` -------------------------------- ### ActionRetrier Testing Setup Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Provides an example of how to set up testing for actions managed by Action Retrier, likely using a testing framework like Vitest. This helps ensure that retry logic and callbacks function as expected. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; import { test, expect } from "vitest"; // Mock or stub external dependencies if necessary // Define a test action async function flakyAction(input: number): Promise { if (Math.random() < 0.7) { // Simulate failure 70% of the time throw new Error("Action failed!"); } return input * 2; } test("ActionRetrier handles retries correctly", async () => { const retrier = new ActionRetrier({}); // Mock the underlying execution to control success/failure for testing // In a real test, you might mock the actual action or its dependencies const mockAction = vi.fn(flakyAction); // Run the action with specific retry configuration for the test const result = await retrier.run(mockAction, { args: 5, retry: { maxAttempts: 5, initialDelayMs: 10 } // Short delay for test }); // Assertions expect(result).toBe(10); // Assuming the action eventually succeeds expect(mockAction).toHaveBeenCalledAtLeastOnce(); // Add more assertions to check number of calls, final result, etc. }); test("ActionRetrier onComplete callback is called", async () => { const onCompleteMock = vi.fn(); const retrier = new ActionRetrier({ onComplete: onCompleteMock }); await retrier.run(flakyAction, { args: 10, retry: { maxAttempts: 2 } }); expect(onCompleteMock).toHaveBeenCalledTimes(1); // Assert on the arguments passed to onCompleteMock }); ``` -------------------------------- ### Setup Action Retrier and Basic Action Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/08-usage-examples.md Configure the ActionRetrier with your Convex components and define a simple internal action that can be run asynchronously. This is the initial setup for using the retrier. ```typescript // convex/index.ts import { ActionRetrier } from "@convex-dev/action-retrier"; import { components } from "./_generated/api"; export const retrier = new ActionRetrier(components.actionRetrier); export const myAction = internalAction({ args: { data: v.string() }, handler: async (ctx, args) => { console.log("Processing:", args.data); return { status: "done" }; }, }); export const kickoff = mutation({ args: { data: v.string() }, handler: async (ctx, args) => { const runId = await retrier.run( ctx, internal.index.myAction, { data: args.data } ); return runId; }, }); ``` -------------------------------- ### Debug Log Output Example Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/07-error-handling-and-recovery.md Example log output when debug logging is enabled for the Action Retrier. This shows the detailed execution flow, including start, execution, and finish times. ```text DEBUG: Started run abc123 @ 1720000000000 DEBUG: Executing run abc123 DEBUG: Finished executing run abc123 (45.67ms) DEBUG: Finishing an execution of abc123 INFO: Run abc123 succeeded. ``` -------------------------------- ### Install Action Retrier Package Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Install the action-retrier package using npm. This command is necessary if you encounter 'Cannot find module "@convex-dev/action-retrier"' errors. ```bash npm install @convex-dev/action-retrier npm install # Install dependencies if needed ``` -------------------------------- ### start Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/04-public-mutations-and-queries.md Creates a new run and schedules its initial execution. This mutation is not typically called directly; use ActionRetrier.run() instead. ```APIDOC ## start mutation ### Description Creates a new run and schedules its initial execution. Called internally by `ActionRetrier.run()`, `ActionRetrier.runAt()`, and `ActionRetrier.runAfter()`. ### Arguments - **functionHandle** (string) - Serialized function handle created by `createFunctionHandle()` from the action reference. - **functionArgs** (any) - Arguments to pass to the action. Validated by Convex before reaching this mutation. - **options** (Options) - Retry configuration including backoff, max failures, and optional onComplete callback. ### Return value - **string** - The run ID that uniquely identifies the created run. ### Throws Error if the function handle is invalid or the options are malformed. ### Source `src/component/public.ts:6-21` ``` -------------------------------- ### Verify Action Retrier Installation Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Use this query to verify that the Action Retrier component is installed correctly. Ensure there are no TypeScript errors and the query compiles. ```typescript // convex/test.ts import { query } from "./_generated/server"; import { runIdValidator } from "@convex-dev/action-retrier"; import { v } from "convex/values"; export const test = query({ args: { runId: v.optional(runIdValidator) }, handler: async (ctx, args) => { return { installed: true }; }, }); ``` -------------------------------- ### Build One-Off Package Source: https://github.com/get-convex/action-retrier/blob/main/CONTRIBUTING.md Cleans the project, installs dependencies, and packages the project for distribution. ```sh npm run clean npm ci npm pack ``` -------------------------------- ### Install Action Retrier in Convex Project Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Integrate the action retrier component into your Convex project by importing and using the `actionRetrier` in your `convex/convex.config.ts` file. No additional configuration is needed beyond this setup. ```typescript import { defineApp } from "convex/server"; import actionRetrier from "@convex-dev/action-retrier/convex.config.js"; const app = defineApp(); app.use(actionRetrier); export default app; ``` -------------------------------- ### Verification Procedures with Test Code Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Provides example code for verifying the installation and basic functionality of Action Retrier. This typically involves running a simple action and checking its output or status. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; async function testAction() { console.log("Test action executed."); return "success"; } async function verifyInstallation() { const retrier = new ActionRetrier({}); try { const result = await retrier.run(testAction, { args: {}, retry: { maxAttempts: 1 } // Ensure it runs only once for verification }); if (result === "success") { console.log("Action Retrier installation verified successfully!"); } else { console.error("Verification failed: Unexpected result.", result); } } catch (error) { console.error("Action Retrier installation verification failed:", error); } } verifyInstallation(); ``` -------------------------------- ### Check Installed Action Retrier Version Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md View the currently installed version of the Action Retrier package. ```bash npm list @convex-dev/action-retrier ``` -------------------------------- ### Start New Run Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/05-internal-actions-and-mutations.md Initializes a new run record and schedules its first execution. This function is called by the `start` public mutation. ```typescript export async function startRun( ctx: MutationCtx, functionHandle: string, functionArgs: any, options: Options, ) ``` -------------------------------- ### ActionRetrier Scheduling Examples Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Demonstrates using `runAt` and `runAfter` for scheduling actions. `runAt` schedules for a precise future datetime, while `runAfter` schedules after a specified duration. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; const retrier = new ActionRetrier({}); const specificTime = new Date(); specificTime.setHours(specificTime.getHours() + 1); // 1 hour from now // Schedule to run at a specific time await retrier.runAt(myAction, { args: { /* ... */ }, runAt: specificTime }); // Schedule to run after a delay await retrier.runAfter(myAction, { args: { /* ... */ }, runAfter: 1000 * 60 * 15 // 15 minutes from now }); ``` -------------------------------- ### Install Action Retrier NPM Package Source: https://github.com/get-convex/action-retrier/blob/main/README.md Add the action-retrier package to your project's dependencies using npm. ```sh npm install @convex-dev/action-retrier ``` -------------------------------- ### Project Structure Example Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Illustrates a typical project structure for a Convex application utilizing the Action Retrier. This helps in organizing files and understanding where different components fit within the project. ```plaintext my-convex-project/ ├── convex/ │ ├── actions.ts │ ├── mutations.ts │ ├── queries.ts │ ├── _actions/ │ │ └── myActionRetrier.ts <-- ActionRetrier setup and usage │ ├── types.ts │ └── package.json ├── frontend/ │ ├── src/ │ │ └── App.tsx │ └── package.json ├── package.json └── tsconfig.json ``` -------------------------------- ### Example Log Output Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/09-architecture-and-internals.md Illustrates the format and content of logs generated by the system, including timestamps, log levels, and execution details. These logs are visible in the Convex dashboard. ```text DEBUG: Started run abc123 @ 1720000000000 DEBUG: Scheduled heartbeat for abc123 in 10052ms: scheduler_id_xyz DEBUG: Executing run abc123 DEBUG: Finished executing abc123 (45.67ms) INFO: Run abc123 succeeded. ``` -------------------------------- ### retrier.run Source: https://github.com/get-convex/action-retrier/blob/main/README.md Starts an action run with the Action Retrier, handling retries and optional callbacks. ```APIDOC ## retrier.run ### Description Initiates an action to be run by the Action Retrier. The retrier will automatically handle retries on failure with exponential backoff. ### Method `retrier.run(ctx, action, args, options)` ### Endpoint N/A (This is an SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters for `run` method: - **ctx** (object) - Required - The Convex context object. - **action** (function) - Required - The Convex action or internal action function to execute. - **args** (object) - Optional - The arguments to pass to the action. - **options** (object) - Optional - Configuration for the run. - **initialBackoffMs** (number) - Optional - Overrides the `initialBackoffMs` from the constructor for this specific run. - **base** (number) - Optional - Overrides the `base` from the constructor for this specific run. - **maxFailures** (number) - Optional - Overrides the `maxFailures` from the constructor for this specific run. - **onComplete** (function) - Optional - A mutation function to call upon completion of the action. It receives `runId` and `result` as arguments. ### Request Example ```ts // Basic usage const runId = await retrier.run(ctx, internal.module.myAction, { arg: 123 }); // With options to override backoff and specify a callback const runId = await retrier.run( ctx, internal.index.exampleAction, { failureRate: 0.8 }, { initialBackoffMs: 125, base: 2.71, maxFailures: 3, onComplete: internal.index.exampleCallback, } ); ``` ### Response #### Success Response (200) - **runId** (string) - The unique identifier for this action run. #### Response Example ```json { "runId": "some-unique-run-id" } ``` ### Error Handling - If the action fails after all retries, the `onComplete` callback will be invoked with `result.type === "failed"`. - If the action is canceled, the `onComplete` callback will be invoked with `result.type === "canceled"`. ``` -------------------------------- ### Start Mutation Handler for Action Retrier Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/09-architecture-and-internals.md Handles the initial recording of a run, including function details, arguments, options, and scheduling the first execution. It also sets up a heartbeat. ```typescript // Insert run record run = { functionHandle: handle, functionArgs: args, options: options, state: { type: "inProgress", startTime }, numFailures: 0, } runId = ctx.db.insert("runs", run) // Schedule execution schedulerId = ctx.scheduler.runAt(startTime, execute, { runId }) // Update run with scheduler ID run.state.schedulerId = schedulerId ctx.db.replace("runs", runId, run) // Schedule heartbeat heartbeatId = ctx.scheduler.runAt(nextHeartbeat, heartbeat, { runId }) return runId ``` -------------------------------- ### ActionRetrier Client Usage Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Demonstrates basic usage of the ActionRetrier client, including instantiation and running an action. This is a starting point for integrating retries into your Convex actions. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; const retrier = new ActionRetrier({ // Configuration options here }); // Example action to retry async function myAction(args: any) { // ... action logic ... return "action result"; } // Run the action with retries const result = await retrier.run(myAction, { args: { /* ... */ } }); ``` -------------------------------- ### Example: Scheduling Actions at Specific Times Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Demonstrates scheduling actions using both relative delays and absolute timestamps, including running in one minute, at 9 AM tomorrow, and at a future timestamp 24 hours from now. ```typescript // Run in 1 minute const in1min = await retrier.runAfter(ctx, 60000, internal.module.myAction, {}); // Run at 9 AM tomorrow const tomorrow9am = new Date(); tomorrow9am.setDate(tomorrow9am.getDate() + 1); tomorrow9am.setHours(9, 0, 0, 0); const runId = await retrier.runAt(ctx, tomorrow9am.getTime(), internal.module.myAction, {}); // Run at a future timestamp const futureTime = Date.now() + (24 * 60 * 60 * 1000); // 24 hours from now const runId = await retrier.runAt(ctx, futureTime, internal.module.myAction, {}); ``` -------------------------------- ### Initialize Action Retrier Source: https://github.com/get-convex/action-retrier/blob/main/README.md Import and initialize the ActionRetrier component in your Convex project. This sets up the retrier to use the installed component. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; import { components } from "./convex/_generated/server"; const retrier = new ActionRetrier(components.actionRetrier); ``` -------------------------------- ### exampleCallback Mutation Source: https://github.com/get-convex/action-retrier/blob/main/README.md An example mutation handler for processing the result of a retried action. ```APIDOC ## exampleCallback Mutation ### Description An example mutation that can be used as an `onComplete` callback for `retrier.run`. It handles different completion states of the action (success, failure, canceled). ### Method `internalMutation` ### Endpoint N/A (This is an SDK method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters for `exampleCallback`: - **args.id** (`runIdValidator`) - Required - The ID of the completed run. - **args.result** (`runResultValidator`) - Required - An object containing the result of the action run. It has a `type` property which can be 'success', 'failed', or 'canceled'. - If `type` is 'success', it contains `returnValue`. - If `type` is 'failed', it contains `error`. - If `type` is 'canceled', it contains no additional properties. ### Request Example ```ts // Inside convex/index.ts import { runResultValidator, runIdValidator } from "@convex-dev/action-retrier"; export const exampleCallback = internalMutation({ args: { id: runIdValidator, result: runResultValidator }, handler: async (ctx, args) => { if (args.result.type === "success") { console.log("Action succeeded with return value:", args.result.returnValue); } else if (args.result.type === "failed") { console.log("Action failed with error:", args.result.error); } else if (args.result.type === "canceled") { console.log("Action was canceled."); } }, }); ``` ### Response N/A (Mutation handler does not return a value directly to the caller of `retrier.run`) ``` -------------------------------- ### Customizing ActionRetrier with Options Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/02-types.md Example of creating an ActionRetrier instance with custom options, such as a longer initial backoff, a different exponential backoff base, and a higher maximum number of failures. ```typescript const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 500, base: 3, maxFailures: 5, }); ``` -------------------------------- ### User Initiates Action Retrier Run Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/09-architecture-and-internals.md The entry point for initiating a retried action. It involves creating a serialized function handle and starting a mutation to record the run. ```typescript User calls: retrier.run(ctx, action, args, options) ↓ createFunctionHandle(action) → serialized handle ↓ ctx.runMutation(public.start, { handle, args, options }) ``` -------------------------------- ### Start Action Run Mutation Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/04-public-mutations-and-queries.md Creates a new run and schedules its initial execution. Use ActionRetrier.run() instead of calling this directly. Throws an error if the function handle is invalid or options are malformed. ```typescript export const start = mutation({ args: { functionHandle: v.string(), functionArgs: v.any(), options: options, }, returns: v.string(), handler: async (ctx, args) => { return await startRun(ctx, args.functionHandle, args.functionArgs, args.options); }, }) ``` -------------------------------- ### Run Convex Codegen Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Execute the Convex code generation command to create type-safe references for the component's functions. This is a required step after installation and configuration. ```bash npx convex codegen ``` -------------------------------- ### Handling RunResult Outcomes Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/02-types.md Example demonstrating how to check the status and result of a run, and then handle success, failure, or cancellation based on the RunResult type. ```typescript const status = await retrier.status(ctx, runId); if (status.type === "completed") { const result = status.result; if (result.type === "success") { console.log("Success:", result.returnValue); } else if (result.type === "failed") { console.error("Failed:", result.error); } else if (result.type === "canceled") { console.log("Canceled"); } } ``` -------------------------------- ### Log Action Completions Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Example of an `onComplete` mutation that logs success, failure, or cancellation of a run. It persists results to the database and can be used to notify users of failures. ```typescript export const logCompletion = internalMutation({ args: onCompleteValidator, handler: async (ctx, args) => { const { runId, result } = args; if (result.type === "success") { console.log(`Run ${runId} succeeded:`, result.returnValue); // Persist success result to database await ctx.db.insert("completedRuns", { runId, status: "success", returnValue: result.returnValue, completedAt: Date.now(), }); } else if (result.type === "failed") { console.error(`Run ${runId} failed:`, result.error); // Notify user of failure await ctx.db.insert("failedRuns", { runId, error: result.error, completedAt: Date.now(), }); } else if (result.type === "canceled") { console.log(`Run ${runId} was canceled`); } }, }); // Use it export const kickoff = mutation({ handler: async (ctx) => { return await retrier.run(ctx, internal.module.myAction, {}, { onComplete: internal.module.logCompletion, }); }, }); ``` -------------------------------- ### Run an Action with ActionRetrier Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Use the instantiated `retrier` to run a Convex action with automatic retry logic. This example shows how to kick off an action and return its run ID. ```typescript // convex/actions.ts import { retrier } from "./retrier.js"; export const kickoffAction = mutation({ handler: async (ctx) => { const runId = await retrier.run(ctx, internal.actions.myAction, {{}}); return runId; }, }); ``` -------------------------------- ### ActionRetrier Pagination with Retries Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Demonstrates how to implement paginated data fetching or processing using Action Retrier. This example shows fetching data page by page and retrying individual page fetches if they fail. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; const retrier = new ActionRetrier({}); async function fetchPage(pageNumber: number) { console.log(`Fetching page ${pageNumber}...`); // Simulate fetching data from an API if (Math.random() < 0.3) { // Simulate occasional failure throw new Error(`Failed to fetch page ${pageNumber}`); } // ... actual API call ... return { data: [`items from page ${pageNumber}`], nextPage: pageNumber + 1 }; } async function fetchPaginatedData(totalPages: number) { const allData = []; let currentPage = 1; while (currentPage <= totalPages) { try { const pageResult = await retrier.run(fetchPage, { args: currentPage, retry: { maxAttempts: 4, initialDelayMs: 500 } // Retry fetching a page if it fails }); allData.push(...pageResult.data); currentPage = pageResult.nextPage; } catch (error) { console.error(`Failed to fetch page ${currentPage} after retries:`, error); // Decide how to handle persistent page fetch failures break; } } return allData; } fetchPaginatedData(5); ``` -------------------------------- ### Write Action Retrier Tests Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Example test case demonstrating how to use the action retrier component within your Convex tests. It checks mutation and query functionalities. ```typescript // convex/actions.test.ts import { test, expect } from "vitest"; import { initConvexTest } from "./test-setup.js"; test("action retrier works", async () => { const t = initConvexTest(); const runId = await t.mutation("actions.kickoffAction", {}); expect(runId).toBeDefined(); const status = await t.query("actions.checkStatus", { runId }); expect(status).toBeDefined(); }); ``` -------------------------------- ### Test Action Retrier Integration with Convex Test Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/08-usage-examples.md Set up and execute tests for the action-retrier component using `convex-test`. This example demonstrates initializing the test environment, registering the component, and performing basic mutation and query operations. ```typescript // convex/test-setup.test.ts import { test, expect } from "vitest"; import { convexTest } from "convex-test"; import schema from "./schema.js"; import component from "@convex-dev/action-retrier/test"; const modules = import.meta.glob("./**/*.*s"); function initConvexTest() { const t = convexTest(schema, modules); component.register(t); return t; } test("action retrier integration", async () => { const t = initConvexTest(); // Start a run const runId = await t.mutation("index.kickoff", { data: "test" }); // Check status let status = await t.query("index.checkStatus", { runId }); expect(status.message || status.success).toBeDefined(); }); ``` -------------------------------- ### Example: Check Run Status Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/02-types.md Demonstrates how to check the status of a run using the `RunStatus` type. This pattern is useful for conditional logic based on whether a run is still executing or has finished. ```typescript const status = await retrier.status(ctx, runId); if (status.type === "inProgress") { console.log("Still running..."); } else { console.log("Finished:", status.result); } ``` -------------------------------- ### ActionRetrier Batch Processing with Notifications Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Shows an example of processing items in batches using Action Retrier and sending notifications upon completion. This pattern is useful for background jobs that process collections of data. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; const retrier = new ActionRetrier({}); async function processBatchItem(item: any) { // Process a single item console.log(`Processing item: ${item.id}`); // ... item processing logic ... return `processed ${item.id}`; } async function processBatch(items: any[]) { const results = []; for (const item of items) { const result = await retrier.run(processBatchItem, { args: item, // Configure retries for individual items if needed retry: { maxAttempts: 3 } }); results.push(result); } // Send a notification after all items are processed console.log("Batch processing complete. Sending notification..."); // ... notification logic ... return results; } const dataItems = [{ id: 1 }, { id: 2 }, { id: 3 }]; await processBatch(dataItems); ``` -------------------------------- ### Deploy to Convex Production Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Push your changes to Convex production using this command. ```bash # Push changes to Convex production npx convex deploy ``` -------------------------------- ### Initialize Action Retrier with Recommended Defaults Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Initialize the Action Retrier with default performance settings, suitable for most applications. ```typescript const retrier = new ActionRetrier(components.actionRetrier); ``` -------------------------------- ### ActionRetrier Configuration Options Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/README.md Details the configuration options available for the ActionRetrier, both for the constructor and per-run. ```APIDOC ## Configuration Reference ### Constructor Options (all optional) | Option | Type | Default | Purpose | |--------|------|---------|---------| | initialBackoffMs | number | 250 | First retry delay | | base | number | 2 | Exponential backoff multiplier | | maxFailures | number | 4 | Max retries (5 total attempts) | | logLevel | LogLevel | INFO | Logging verbosity | ### Environment Variables | Variable | Values | Default | |----------|--------|---------| | ACTION_RETRIER_LOG_LEVEL | DEBUG, INFO, WARN, ERROR | INFO | ### Per-Run Options (in `RunOptions`) - All constructor options (can override) - `onComplete` — mutation callback - `runAt` — absolute timestamp - `runAfter` — relative delay ``` -------------------------------- ### RunState Union Type - InProgress State Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/09-architecture-and-internals.md Defines the 'inProgress' state for a run, including the scheduler ID, start time, and type. ```typescript { type: "inProgress", schedulerId?: Id<"_scheduled_functions">, // Scheduler ID startTime: number, // Scheduled execution time } ``` -------------------------------- ### Schedule Execution at Absolute Timestamp Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Schedules an action to run at a specific Unix timestamp in milliseconds. If the timestamp is in the past, execution starts immediately. ```typescript const runId = await retrier.runAt(ctx, Date.now() + 60000, internal.module.myAction, args); ``` -------------------------------- ### Deploy New Version Source: https://github.com/get-convex/action-retrier/blob/main/CONTRIBUTING.md Releases a new version of the project. ```sh npm run release ``` -------------------------------- ### Use runIdValidator in a query Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/03-validators.md Example of using `runIdValidator` to validate the `runId` argument in a Convex query. Ensures type safety for the `runId` parameter. ```typescript import { runIdValidator } from "@convex-dev/action-retrier"; import { query } from "./_generated/server"; export const getRunStatus = query({ args: { runId: runIdValidator }, handler: async (ctx, args) => { // args.runId is now typed as RunId const status = await retrier.status(ctx, args.runId); return status; }, }); ``` -------------------------------- ### Create Action Retrier Instance in Convex Source: https://github.com/get-convex/action-retrier/blob/main/README.md Instantiate the ActionRetrier in your Convex project, pointing it to the installed component. This makes the retrier available for use in your actions and mutations. ```typescript // convex/index.ts import { ActionRetrier } from "@convex-dev/action-retrier"; import { components } from "./_generated/api"; export const retrier = new ActionRetrier(components.actionRetrier); ``` -------------------------------- ### Action Retrier with Slow Backoff Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Configure the Action Retrier for slow operations or rate-limited APIs. Starts with a longer initial backoff and increases the delay more gradually. ```typescript const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 5000, // Start after 5 seconds base: 1.5, // Increase more gradually maxFailures: 10, }); ``` -------------------------------- ### Configure Action Retrier with Completion Callback Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/02-types.md Demonstrates how to set up an internal mutation for completion handling and then use it within the RunOptions when running an action. The onComplete callback receives the runId and result upon action completion. ```typescript export const completion = internalMutation({ args: { runId: runIdValidator, result: runResultValidator }, handler: async (ctx, args) => { console.log("Run finished:", args.result); }, }); export const kickoff = mutation({ handler: async (ctx) => { const runId = await retrier.run( ctx, internal.module.myAction, {}, { initialBackoffMs: 100, onComplete: internal.module.completion, } ); }, }); ``` -------------------------------- ### Project Structure Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/README.md Illustrates the directory structure of the Action Retrier component, highlighting key files and their purposes within the 'src' directory. ```tree src/ ├── client/ │ └── index.ts # ActionRetrier class (public API) ├── component/ │ ├── public.ts # Public mutations and queries │ ├── run.ts # Internal actions and mutations │ ├── schema.ts # Database schema and types │ ├── utils.ts # Logger utility │ ├── crons.ts # Cron job for cleanup │ ├── convex.config.ts # Component configuration │ └── _generated/ # Auto-generated Convex files └── test.ts # Test helper export ``` -------------------------------- ### Regenerate TypeScript Types Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Regenerate TypeScript types and check for errors after installation or configuration changes. This helps resolve TypeScript errors caused by stale generated types. ```bash npx convex codegen npx tsc --noEmit # Check for errors ``` -------------------------------- ### Deploy Alpha Release Source: https://github.com/get-convex/action-retrier/blob/main/CONTRIBUTING.md Releases an alpha version of the project. ```sh npm run alpha ``` -------------------------------- ### ActionRetrier Run Methods Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/MANIFEST.txt Illustrates various methods for running actions with different scheduling and status checking options. Use `runAt` for specific future execution, `runAfter` for delayed execution, and `status` to check the state of a run. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; const retrier = new ActionRetrier({}); // Run an action at a specific time await retrier.runAt(myAction, { args: { /* ... */ }, runAt: new Date(Date.now() + 1000 * 60 * 5) // 5 minutes from now }); // Run an action after a delay await retrier.runAfter(myAction, { args: { /* ... */ }, runAfter: 1000 * 60 * 10 // 10 minutes from now }); // Check the status of a run const status = await retrier.status("some-run-id"); console.log(status); ``` -------------------------------- ### Client Code to Kickoff Action Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/08-usage-examples.md This client-side code initiates the asynchronous action defined in Convex by calling the 'kickoff' mutation. It logs the returned run ID. ```typescript // Client code const runId = await runKickoff({ data: "test" }); console.log("Run started:", runId); ``` -------------------------------- ### Use onCompleteValidator in an Internal Mutation Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/03-validators.md An example of defining an internal mutation handler using `onCompleteValidator` for its arguments. This ensures that the `runId` and `result` passed to the handler are correctly validated. ```typescript import { onCompleteValidator } from "@convex-dev/action-retrier"; import { internalMutation } from "./_generated/server"; export const handleCompletion = internalMutation({ args: onCompleteValidator, handler: async (ctx, args) => { console.log(`Run ${args.runId} completed with result:`, args.result); }, }); ``` -------------------------------- ### runAt Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/01-action-retrier-client.md Like `run()`, but schedules the action to execute no earlier than a specific Unix timestamp in milliseconds. Useful for scheduling actions at a precise future time. ```APIDOC ## runAt ### Description Like `run()`, but schedules the action to execute no earlier than a specific Unix timestamp in milliseconds. Useful for scheduling actions at a precise future time. ### Method `async runAt>(ctx: MutationCtx | ActionCtx, runAtTimestampMs: number, reference: F, args?: FunctionArgs, options?: RunOptions): Promise` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ctx | `MutationCtx | ActionCtx` | Yes | Convex context from a mutation or action. | | runAtTimestampMs | `number` | Yes | Unix timestamp in milliseconds when execution should begin. If this time is in the past, execution begins immediately. | | reference | `FunctionReference<"action", FunctionVisibility>` | Yes | Internal action reference. | | args | `FunctionArgs` | No | Action arguments. | | options | `RunOptions` | No | Per-run configuration. | ### Return Value A `RunId` string. ### Example ```typescript export const scheduleAction = mutation({ handler: async (ctx) => { const targetTime = Date.now() + 60000; // 1 minute from now const runId = await retrier.runAt( ctx, targetTime, internal.module.myAction, {} ); return runId; }, }); ``` ``` -------------------------------- ### Use onCompleteValidator in an onComplete Callback Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/03-validators.md Example of using `onCompleteValidator` to define the arguments for an internal mutation that handles the completion of an action. This ensures type safety for `args.runId` and `args.result`. ```typescript import { onCompleteValidator } from "@convex-dev/action-retrier"; import { internalMutation } from "./_generated/server"; export const onComplete = internalMutation({ args: onCompleteValidator, handler: async (ctx, args) => { console.log("Run completed:", args.runId, args.result); }, }); ``` -------------------------------- ### Basic Action Retrier Usage Source: https://github.com/get-convex/action-retrier/blob/main/README.md Demonstrates the basic usage of the ActionRetrier component by initializing it and then using its `run` method to execute an action that might fail. The retrier automatically handles retries. ```typescript import { ActionRetrier } from "@convex-dev/action-retrier"; import { components } from "./convex/_generated/server"; const retrier = new ActionRetrier(components.actionRetrier); // `retrier.run` will automatically retry your action up to four times before giving up. await retrier.run(ctx, internal.module.myAction, { arg: 123 }); ``` -------------------------------- ### Action Retrier with Fast Backoff Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/06-configuration-and-environment.md Configure the Action Retrier for fast, bursty failures like network timeouts. Starts with a quick initial backoff and doubles the delay with each subsequent failure. ```typescript const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 100, // Start quick base: 2, // Double each time maxFailures: 5, }); ``` -------------------------------- ### Instantiate ActionRetrier with Custom Configuration Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Create an instance of the ActionRetrier with custom configuration options, such as `initialBackoffMs`, `base`, `maxFailures`, and `logLevel`. This allows fine-tuning the retry behavior. ```typescript // convex/retrier.ts import { ActionRetrier } from "@convex-dev/action-retrier"; import { components } from "./_generated/server"; export const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 250, base: 2, maxFailures: 4, logLevel: "INFO", }); ``` -------------------------------- ### Idempotent Action Design Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/07-error-handling-and-recovery.md Design actions to be idempotent to safely handle retries. The 'GOOD' example demonstrates checking if an action has already been performed before executing it again, preventing duplicate side effects. ```typescript // BAD: Not idempotent export const sendNotification = internalAction({ handler: async (ctx) => { await emailService.send(user.email, "Hello"); // If retried, sends email again! }, }); // GOOD: Idempotent export const sendNotification = internalAction({ args: { userId: v.string(), emailId: v.string() }, handler: async (ctx, args) => { // Check if already sent const sent = await ctx.runQuery(internal.sent.exists, { emailId: args.emailId, }); if (sent) { return; // Already sent, don't send again } // Send email await emailService.send(user.email, "Hello"); // Mark as sent await ctx.runMutation(internal.sent.mark, { emailId: args.emailId }); }, }); ``` -------------------------------- ### Initialize Convex Test Helper Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Set up the test helper for writing tests with the action-retrier component. Ensure schema and component modules are imported. ```typescript // convex/test-setup.ts import { convexTest } from "convex-test"; import schema from "./schema.js"; import component from "@convex-dev/action-retrier/test"; const modules = import.meta.glob("./**/*.*s"); export function initConvexTest() { const t = convexTest(schema, modules); component.register(t); return t; } ``` -------------------------------- ### Use runResultValidator in an internal mutation Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/03-validators.md Example of using `runResultValidator` and `runIdValidator` to handle different run result types in a Convex internal mutation. Demonstrates type-safe handling of run results. ```typescript import { runResultValidator, runIdValidator } from "@convex-dev/action-retrier"; import { internalMutation } from "./_generated/server"; export const onComplete = internalMutation({ args: { runId: runIdValidator, result: runResultValidator, }, handler: async (ctx, args) => { if (args.result.type === "success") { console.log("Success:", args.result.returnValue); } else if (args.result.type === "failed") { console.error("Failed:", args.result.error); } else { console.log("Canceled"); } }, }); ``` -------------------------------- ### runAfter Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/01-action-retrier-client.md Like `run()`, but schedules the action to execute after a specific delay from the call time, not from when it reaches the front of the queue. ```APIDOC ## runAfter ### Description Like `run()`, but schedules the action to execute after a specific delay from the call time, not from when it reaches the front of the queue. ### Method `async runAfter>(ctx: MutationCtx | ActionCtx, runAfterMs: number, reference: F, args?: FunctionArgs, options?: RunOptions): Promise` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | ctx | `MutationCtx | ActionCtx` | Yes | Convex context from a mutation or action. | | runAfterMs | `number` | Yes | Delay in milliseconds from the current time to wait before starting execution. | | reference | `FunctionReference<"action", FunctionVisibility>` | Yes | Internal action reference. | | args | `FunctionArgs` | No | Action arguments. | | options | `RunOptions` | No | Per-run configuration. | ### Return Value A `RunId` string. ### Example ```typescript export const delayedAction = mutation({ handler: async (ctx) => { const runId = await retrier.runAfter( ctx, 5000, // 5 seconds internal.module.myAction, { data: "test" } ); return runId; }, }); ``` ``` -------------------------------- ### Configure ActionRetrier Constructor Options Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/10-component-installation.md Instantiate ActionRetrier with custom options to control backoff strategy, maximum failures, and logging. All options are optional. ```typescript const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 500, // Start backoff at 500ms base: 2, // Double each retry maxFailures: 5, // Up to 6 attempts total logLevel: "DEBUG", // Verbose logging }); ``` -------------------------------- ### Run Project Tests Source: https://github.com/get-convex/action-retrier/blob/main/CONTRIBUTING.md Cleans the project, builds, typechecks, lints, and runs tests. ```sh npm run clean npm run build npm run typecheck npm run lint npm run test ``` -------------------------------- ### Delay Action Execution Source: https://github.com/get-convex/action-retrier/blob/main/_autodocs/01-action-retrier-client.md Schedules an action to execute after a specific delay from the call time. Use this when the exact start time is less critical than a minimum waiting period. Returns a run ID for tracking. ```typescript async runAfter>( ctx: MutationCtx | ActionCtx, runAfterMs: number, reference: F, args?: FunctionArgs, options?: RunOptions ): Promise ``` ```typescript export const delayedAction = mutation({ handler: async (ctx) => { const runId = await retrier.runAfter( ctx, 5000, // 5 seconds internal.module.myAction, { data: "test" } ); return runId; }, }); ``` -------------------------------- ### ActionRetrier Constructor Source: https://github.com/get-convex/action-retrier/blob/main/README.md Initialize the ActionRetrier component, optionally configuring backoff behavior. ```APIDOC ## ActionRetrier Constructor ### Description Initializes a new instance of the ActionRetrier. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters for Constructor - **components.actionRetrier** (object) - Required - The installed ActionRetrier component from `convex.config.ts`. - **options** (object) - Optional - Configuration for backoff behavior. - **initialBackoffMs** (number) - Optional - The initial delay in milliseconds before retrying (default: 250). - **base** (number) - Optional - The base for the exponential backoff calculation (default: 2). - **maxFailures** (number) - Optional - The maximum number of times to retry the action (default: 4). ### Request Example ```ts // Default configuration const retrier = new ActionRetrier(components.actionRetrier); // Custom configuration const retrier = new ActionRetrier(components.actionRetrier, { initialBackoffMs: 10000, base: 10, maxFailures: 4, }); ``` ### Response N/A (Constructor does not return a value) ```