///
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';