try a convenience thing for scheduling providers
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -11,17 +11,10 @@ import { Logger } from 'winston';
|
||||
|
||||
// @public
|
||||
export interface PluginTaskScheduler {
|
||||
scheduleTask(task: TaskDefinition): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface TaskDefinition {
|
||||
fn: TaskFunction;
|
||||
frequency: Duration;
|
||||
id: string;
|
||||
initialDelay?: Duration;
|
||||
signal?: AbortSignal_2;
|
||||
timeout: Duration;
|
||||
createTaskSchedule(schedule: TaskScheduleDefinition): TaskSchedule;
|
||||
scheduleTask(
|
||||
task: TaskScheduleDefinition & TaskInvocationDefinition,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
@@ -29,6 +22,25 @@ export type TaskFunction =
|
||||
| ((abortSignal: AbortSignal_2) => void | Promise<void>)
|
||||
| (() => void | Promise<void>);
|
||||
|
||||
// @public
|
||||
export interface TaskInvocationDefinition {
|
||||
fn: TaskFunction;
|
||||
id: string;
|
||||
signal?: AbortSignal_2;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface TaskSchedule {
|
||||
run(task: TaskInvocationDefinition): Promise<void>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface TaskScheduleDefinition {
|
||||
frequency: Duration;
|
||||
initialDelay?: Duration;
|
||||
timeout: Duration;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class TaskScheduler {
|
||||
constructor(databaseManager: DatabaseManager, logger: Logger);
|
||||
|
||||
@@ -59,4 +59,31 @@ describe('PluginTaskManagerImpl', () => {
|
||||
60_000,
|
||||
);
|
||||
});
|
||||
|
||||
// This is just to test the wrapper code; most of the actual tests are in
|
||||
// TaskWorker.test.ts
|
||||
describe('createTaskSchedule', () => {
|
||||
it.each(databases.eachSupportedId())(
|
||||
'can run the happy path, %p',
|
||||
async databaseId => {
|
||||
const { manager } = await init(databaseId);
|
||||
|
||||
const fn = jest.fn();
|
||||
await manager
|
||||
.createTaskSchedule({
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromMillis(5000),
|
||||
})
|
||||
.run({
|
||||
id: 'task1',
|
||||
fn,
|
||||
});
|
||||
|
||||
await waitForExpect(() => {
|
||||
expect(fn).toBeCalled();
|
||||
});
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Logger } from 'winston';
|
||||
import { TaskWorker } from './TaskWorker';
|
||||
import { PluginTaskScheduler, TaskDefinition } from './types';
|
||||
import {
|
||||
PluginTaskScheduler,
|
||||
TaskInvocationDefinition,
|
||||
TaskSchedule,
|
||||
TaskScheduleDefinition,
|
||||
} from './types';
|
||||
import { validateId } from './util';
|
||||
|
||||
/**
|
||||
@@ -29,7 +34,9 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async scheduleTask(task: TaskDefinition): Promise<void> {
|
||||
async scheduleTask(
|
||||
task: TaskScheduleDefinition & TaskInvocationDefinition,
|
||||
): Promise<void> {
|
||||
validateId(task.id);
|
||||
|
||||
const knex = await this.databaseFactory();
|
||||
@@ -47,4 +54,12 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
createTaskSchedule(schedule: TaskScheduleDefinition): TaskSchedule {
|
||||
return {
|
||||
run: async task => {
|
||||
await this.scheduleTask({ ...task, ...schedule });
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
export { TaskScheduler } from './TaskScheduler';
|
||||
export type {
|
||||
PluginTaskScheduler,
|
||||
TaskDefinition,
|
||||
TaskFunction,
|
||||
TaskInvocationDefinition,
|
||||
TaskSchedule,
|
||||
TaskScheduleDefinition,
|
||||
} from './types';
|
||||
|
||||
@@ -31,27 +31,11 @@ export type TaskFunction =
|
||||
| (() => void | Promise<void>);
|
||||
|
||||
/**
|
||||
* Options that apply to the invocation of a given task.
|
||||
* Options that control the scheduling of a task.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TaskDefinition {
|
||||
/**
|
||||
* A unique ID (within the scope of the plugin) for the task.
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The actual task function to be invoked regularly.
|
||||
*/
|
||||
fn: TaskFunction;
|
||||
|
||||
/**
|
||||
* An abort signal that, when triggered, will stop the recurring execution of
|
||||
* the task.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
|
||||
export interface TaskScheduleDefinition {
|
||||
/**
|
||||
* The maximum amount of time that a single task invocation can take, before
|
||||
* it's considered timed out and gets "released" such that a new invocation
|
||||
@@ -91,6 +75,43 @@ export interface TaskDefinition {
|
||||
initialDelay?: Duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options that apply to the invocation of a given task.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TaskInvocationDefinition {
|
||||
/**
|
||||
* A unique ID (within the scope of the plugin) for the task.
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The actual task function to be invoked regularly.
|
||||
*/
|
||||
fn: TaskFunction;
|
||||
|
||||
/**
|
||||
* An abort signal that, when triggered, will stop the recurring execution of
|
||||
* the task.
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
}
|
||||
|
||||
/**
|
||||
* A previously prepared task schedule, ready to be invoked.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TaskSchedule {
|
||||
/**
|
||||
* Takes the schedule and executes an actual task using it.
|
||||
*
|
||||
* @param task - The actual runtime properties of the task
|
||||
*/
|
||||
run(task: TaskInvocationDefinition): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deals with the scheduling of distributed tasks, for a given plugin.
|
||||
*
|
||||
@@ -99,15 +120,33 @@ export interface TaskDefinition {
|
||||
export interface PluginTaskScheduler {
|
||||
/**
|
||||
* Schedules a task function for coordinated exclusive invocation across
|
||||
* workers.
|
||||
* workers. This convenience method performs both the scheduling and
|
||||
* invocation in one go.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* If the task was already scheduled since before by us or by another party,
|
||||
* its options are just overwritten with the given options, and things
|
||||
* continue from there.
|
||||
*
|
||||
* @param definition - The task definition
|
||||
* @param task - The task definition
|
||||
*/
|
||||
scheduleTask(task: TaskDefinition): Promise<void>;
|
||||
scheduleTask(
|
||||
task: TaskScheduleDefinition & TaskInvocationDefinition,
|
||||
): Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a task schedule, ready to be invoked at a later time.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This method is useful for pre-creating a schedule in outer code to be
|
||||
* passed into an inner implementation, such that the outer code controls
|
||||
* scheduling while inner code controls implementation.
|
||||
*
|
||||
* @param schedule - The task schedule
|
||||
*/
|
||||
createTaskSchedule(schedule: TaskScheduleDefinition): TaskSchedule;
|
||||
}
|
||||
|
||||
function isValidOptionalDurationString(d: string | undefined): boolean {
|
||||
|
||||
Reference in New Issue
Block a user