@cfxdevkit/executor
Generic background job runner with queues and scheduler.
Install
pnpm
pnpm add @cfxdevkit/executorScope: Generic execution primitives for keeper / off-chain automation systems.
Responsibilities
- Job queue interface (pluggable backends via
createTaskQueue) - Retry with exponential backoff policies (via
RetryPolicyandExecuteOptions) - Gas-aware transaction submission (via
gasPrice,maxFeePerGas,maxPriorityFeePerGasinExecutionContext) - Idempotency support (via
idempotencyKeyinExecuteOptions) - Distributed locking (via
withLock) - Periodic polling (via
createPoller)
Domain-specific automation strategies (DCA, limit orders, etc.) live in
@cfxdevkit/automation and consume this package.
Installation
npm install @cfxdevkit/executorSub-paths
| Sub-path | Exports |
|---|---|
. | 16 symbols |
.
Types
export interface ExecutionContext {
chainId: number;
blockNumber: number;
timestamp: number;
gasPrice?: bigint;
maxFeePerGas?: bigint;
maxPriorityFeePerGas?: bigint;
}
export interface RetryPolicy {
maxRetries: number;
baseDelayMs: number;
}
export interface ExecuteOptions extends RetryPolicy {
idempotencyKey?: string;
context?: Partial<ExecutionContext>;
timeoutMs?: number;
labels?: Record<string, string>;
}
export interface BatchOptions extends ExecuteOptions {
concurrency?: number;
}
export interface TaskQueueOptions extends BatchOptions {
name?: string;
persistent?: boolean;
priorityFn?: (a: ExecutionTask<any>, b: ExecutionTask<any>) => number;
}
export interface PollerContext {
lastExecutionTime: number;
consecutiveFailures: number;
}
export type ExecutionTask<T> = (context: ExecutionContext) => Promise<T> | T;
export type ExecutionResult<T> = {
success: boolean;
value?: T;
error?: Error;
attempts: number;
};
export type PollerTask = (context: PollerContext) => Promise<void> | void;
export interface Poller {
start(): void;
stop(): void;
isRunning: boolean;
}Functions
export declare function execute<T>(
task: ExecutionTask<T>,
options?: ExecuteOptions
): Promise<ExecutionResult<T>>;
export declare function executeBatch<T>(
tasks: ReadonlyArray<ExecutionTask<T>>,
options?: BatchOptions
): Promise<Array<ExecutionResult<T>>>;
export declare function createTaskQueue(
options?: TaskQueueOptions
): {
enqueue<T>(task: ExecutionTask<T>, options?: ExecuteOptions): Promise<ExecutionResult<T>>;
start(): void;
stop(): void;
isRunning: boolean;
};
export declare function createPoller(
task: PollerTask,
intervalMs: number
): Poller;
export declare function withLock<T>(
key: string,
task: () => Promise<T> | T
): Promise<T>;
export declare const __packageName: "@cfxdevkit/executor";Usage
Single execution with retry and idempotency
import { execute } from '@cfxdevkit/executor';
const result = await execute(
async (ctx) => {
// Perform on-chain operation using ctx.gasPrice, etc.
return 'success';
},
{
maxRetries: 3,
baseDelayMs: 500,
idempotencyKey: 'tx-0x123',
context: { chainId: 1, blockNumber: 18000000 }
}
);Batch execution
import { executeBatch } from '@cfxdevkit/executor';
const results = await executeBatch(
[
async (ctx) => task1(ctx),
async (ctx) => task2(ctx),
],
{ maxRetries: 2, context: { chainId: 1 } }
);Task queue with concurrency control
import { createTaskQueue } from '@cfxdevkit/executor';
const queue = createTaskQueue({
concurrency: 5,
maxRetries: 3,
baseDelayMs: 250,
name: 'automation-queue'
});
queue.start();
await queue.enqueue(async (ctx) => {
// Enqueued task
});
// Later...
queue.stop();Poller for periodic checks
import { createPoller } from '@cfxdevkit/executor';
const poller = createPoller(
async (ctx) => {
// Check condition every 10s; ctx.lastExecutionTime and ctx.consecutiveFailures available
},
10_000
);
poller.start();
// poller.stop();Distributed locking
import { withLock } from '@cfxdevkit/executor';
const result = await withLock('dca:account-0x...', async () => {
// Critical section — only one instance runs at a time
});API Reference
See API.md for the full public surface.
Tier
Tier 0 — framework — Must not runtime-import from any higher tier.
API Reference
.
Usage
import { execute, executeBatch, createTaskQueue } from '@cfxdevkit/executor';
const task = async (ctx) => {
return "success";
};
const result = await execute(task);
const batchResults = await executeBatch([task, task]);// Package name identifier for runtime introspection.
export declare const __packageName: "@cfxdevkit/executor";
// Metadata and runtime information for the current task execution.
export interface ExecutionContext {
// Unique ID for this execution instance.
id: string;
// Timestamp when the execution started.
startTime: number;
// Optional labels attached to the task.
labels?: Record<string, string>;
// Reference to the queue if executed within a queue context.
queueName?: string;
}
// Defines how many times a failed task should be retried and the delay between retries.
export interface RetryPolicy {
// Maximum number of retry attempts after initial failure.
maxRetries: number;
// Base delay in milliseconds between retries (applied with exponential backoff).
baseDelayMs: number;
}
// Options such as timeout, labels, and retry behavior for a single task.
export interface ExecuteOptions extends RetryPolicy {
// Maximum duration in milliseconds before the task is considered timed out.
timeoutMs?: number;
// Arbitrary key-value metadata to attach to the task for tracing/debugging.
labels?: Record<string, string>;
}
// Options inherited from ExecuteOptions, plus batch-specific settings like concurrency.
export interface BatchOptions extends ExecuteOptions {
// Maximum number of tasks allowed to run concurrently in the batch.
concurrency?: number;
}
// Queue-specific settings including concurrency, priority, and persistence.
export interface TaskQueueOptions extends BatchOptions {
// Name of the queue for identification and logging.
name?: string;
// Whether to persist queue state (e.g., to disk or remote store).
persistent?: boolean;
// Optional priority function to reorder pending tasks.
priorityFn?: (a: ExecutionTask<any>, b: ExecutionTask<any>) => number;
}
// Runtime context for periodic tasks, including last execution time and metadata.
export interface PollerContext {
// Timestamp of the last successful execution (0 if none yet).
lastExecutionTime: number;
// Number of consecutive failures since last success.
failureCount: number;
// Optional metadata passed at poller creation.
metadata?: Record<string, unknown>;
}
// Interface representing a running poller instance with start/stop capabilities.
export interface Poller {
// Start the poller and begin executing the task at the specified interval.
start(): void;
// Stop the poller and cancel any pending executions.
stop(): void;
// Whether the poller is currently running.
isRunning(): boolean;
}
// A function that performs a unit of work and receives execution context.
export type ExecutionTask<T> = (context: ExecutionContext) => Promise<T> | T;
// Contains the result value, status (success/failure), and optional error details.
export type ExecutionResult<T> = {
// The value returned by the task on success.
value?: T;
// Whether the execution succeeded.
success: boolean;
// Error object if the execution failed.
error?: Error;
};
// A function that performs a periodic background task and receives poller context.
export type PollerTask = (context: PollerContext) => Promise<void> | void;
// Executes a single task with the provided options.
export declare function execute<T>(task: ExecutionTask<T>, options?: ExecuteOptions): Promise<ExecutionResult<T>>;
// Executes a collection of tasks in a batch.
export declare function executeBatch<T>(tasks: ReadonlyArray<ExecutionTask<T>>, options?: BatchOptions): Promise<Array<ExecutionResult<T>>>;
// Initializes a new task queue.
export declare function createTaskQueue(options?: TaskQueueOptions): {
// Enqueue a task to be processed by the queue.
enqueue<T>(task: ExecutionTask<T>, options?: ExecuteOptions): void;
// Start processing tasks from the queue.
start(): void;
// Stop processing tasks and wait for in-flight tasks to finish.
stop(): Promise<void>;
// Number of tasks currently pending in the queue.
pendingCount(): number;
// Number of tasks currently being processed.
activeCount(): number;
};
// Initializes a new poller for periodic tasks.
export declare function createPoller(task: PollerTask, intervalMs: number): Poller;
// Executes a task within a distributed lock.
export declare function withLock<T>(key: string, task: () => Promise<T> | T): Promise<T>;Last updated on