/// import Logger from 'bunyan'; import TypedEmitter from 'typed-emitter'; import Sequelize from 'sequelize'; import { Duration } from 'moment-timezone'; import { TimestampHelper } from './helpers'; import { JobAttributes, JobInstance } from './models/job'; import { JobModel } from './models/index'; import { JobSet } from './types'; export declare const DEFAULT_MAX_RESTARTS_ON_FAILURE = 3; export declare const DEFAULT_BACKOFF = 60000; export type PendingJobs = { [name: string]: number; }; export interface Events { /** * @description A list of jobs that have lagged and have not been restarted */ lagged: (jobs: JobAttributes[]) => void; /** * @description a job that has been updated to run at the time provided */ reset: (job: JobAttributes, nextRunAt: string) => void; /** * @description Job duration (only available when wrapped with the timestamp helper) */ duration: (job: JobInstance, timeSecs: number, success: boolean) => void; /** * @description An object of job names against pending jobs to run */ pending: (data: PendingJobs) => void; } export type JobContext = { job?: JobInstance; }; export type PublishableTask = { publish: (...args: any) => Promise; [key: string]: any; }; export type TaskCallback = ((data: T, context?: C) => Promise) | ((data?: T, context?: C) => Promise) | ((data: T, context: C) => Promise); export type Tasks = { [name: string]: TaskCallback | PublishableTask; }; export interface JobSchedulerInterface { logger: Logger; databaseUri: string; /** * @description After how many minutes should the job be considered laggy * @default [DEFAULT_LAG=6] */ lagInMinutes?: number; /** * @description After how many minutes, should the job be considered blocked * @default [DEFAULT_BLOCKED_DURATION=10] */ blockedInMinutes?: number; /** * @description Default run interval time in seconds * @default [DEFAULT_RUN_INTERVAL=5000] */ defaultRunInterval?: number; /** * @description Jobs that are risky to restart, these are restarted according to their runtime rules * @example ['payments'] */ jobsRiskyToRestart: string[]; /** * @description Jobs that are safe to restart without implications * @example ['abandoned-carts-task', 'purge-carts-task'] */ jobsSafeToRestart: string[]; /** * @description Custom duration (restart after) setting for jobs * @example { 'order-schedule-reminder': moment.duration(30, 'minutes') //Start after 30 minutes of being laggy }; */ jobsCustomRestart: { [name: string]: Duration; }; /** * @description Event emitter for events such as jobs that are laggy, blocked, restarted, etc. */ events?: TypedEmitter; /** * @description the name of the job against the function to call * @example * { 'abandoned-carts-task': taskRunner(abandonedCartsTask), 'purge-carts-task': taskRunner(purgeCartsTask) } */ tasks: Tasks; /** * @description Register all tasks with the timestamp helper * Timestamp helper will perform the following: * 1. Adds an accepted at timestamp (as the current timestamp) on the job to signal the job was accepted at this time * 2. Runs the callback (whatever the task is) * 3. When the callback runs successfully without any issues, it calculates the next run at for the job using its lunartick (https://www.npmjs.com/package/lunartick) rule and adds the following to the job * - queued: false //signalling the job is now over and ready to be picked up at the next run time * - nextRunAt: timestamp //time to pick up the job * - lastFinishedAt: timestamp //when did the job finish * 4. If the callback fails for some reason, it adds a failure to the job and reruns it with a backoff * NOTE - It doesn't wrap publishable callbacks, to wrap publishable callbacks use the exported {timestampHelperFactory} * @default(false) */ wrapAllTasksWithTimestampHelper?: boolean; /** * @description Number of jobs to enqueue at a time */ enqueueLimit?: number; /** * @description Backoff timeout for retry * @default 60000 */ backOffMs?: number; /** * @description Number of restarts on failure before the job is not retried again * @default 3 */ maxRestartsOnFailure?: number; /** * @description Namespace to select jobs (column - namespace) * By default jobs are not selected by namespace */ namespace?: string; } /** * This scheduler works on the assumption that the database provided should have a jobs table with the following schema * "column_name","column_default","is_nullable","data_type" "id",,"NO","uuid" "name",,"NO","character varying" "data","'{}'::jsonb","YES","jsonb" "last_finished_at",,"YES","timestamp with time zone" "last_modified_by",,"YES","character varying" "last_run_at",,"YES","timestamp with time zone" "next_run_at",,"YES","timestamp with time zone" "repeat_interval",,"YES","character varying" "type",,"YES","character varying" "fail_reason","'{}'::jsonb","YES","jsonb" "failed_at",,"YES","timestamp with time zone" "queued","false","YES","boolean" "created_at","now()","NO","timestamp with time zone" "updated_at","now()","NO","timestamp with time zone" "deleted_at",,"YES","timestamp with time zone" "timezone","'UTC'::character varying","NO","character varying" "accepted_at",,"YES","timestamp with time zone" "priority","1","NO","integer" */ /** * @deprecated Use @ordermentum/scheduler instead. */ export declare class JobScheduler implements JobSchedulerInterface { logger: Logger; lagInMinutes: number; blockedInMinutes: number; defaultRunInterval: number; databaseUri: string; jobsRiskyToRestart: string[]; jobsSafeToRestart: string[]; jobsCustomRestart: { [name: string]: Duration; }; events: TypedEmitter; tasks: Tasks; sequelize: Sequelize.Sequelize; Job: JobModel; allJobs: string[]; timestampHelper: TimestampHelper; wrapAllTasksWithTimestampHelper: boolean; enqueueLimit: number; backOffMs: number; maxRestartsOnFailure: number; paused: boolean; exiting: boolean; startupCheck: boolean; currentTimeout?: ReturnType; namespace?: string; enqueueJobsQuery: string; heartbeat: number; timeout: number; processing: boolean; processingCount: number; constructor({ logger, databaseUri, jobsSafeToRestart, jobsCustomRestart, jobsRiskyToRestart, lagInMinutes, blockedInMinutes, tasks, defaultRunInterval, events, wrapAllTasksWithTimestampHelper, enqueueLimit, backOffMs, maxRestartsOnFailure, namespace, }: JobSchedulerInterface); /** * @description Wraps the callbacks with the helpers that do the following: * - if a publishable callback, wraps the task with a task runner helper that publishes job data by calling publish on the callback * - if {wrapAllTasksWithTimestampHelper} is true, wraps the task with a timestamp helper {timestampHelperFactory} */ wrapTasks: (tasks: Tasks) => Tasks; fetchAndEnqueueJobs: () => Promise; /** * @description Processes a batch of jobs. Will not exit early if the scheduler is terminating, * which is by design to not leave the batch partially processed. * @param rows - The batch of jobs to process * @returns A boolean indicating whether the jobs were processed successfully */ publishMessages: (rows: JobSet[]) => Promise; queueScheduledJobs: () => Promise; beat(): void; healthCheck(): Promise; pause(): Promise; resume(): Promise; /** * Terminates the scheduler and waits for any currently executing tasks to complete */ terminate(): Promise; init(): Promise; runScheduledJobs: (waitTime?: number) => Promise; } export * from './helpers';