backend-tasks: Introduce human friendly scheduling
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -9,6 +9,18 @@ import { DatabaseManager } from '@backstage/backend-common';
|
||||
import { Duration } from 'luxon';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
// @public
|
||||
export type HumanDuration = {
|
||||
years?: number;
|
||||
months?: number;
|
||||
weeks?: number;
|
||||
days?: number;
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface PluginTaskScheduler {
|
||||
createScheduledTaskRunner(schedule: TaskScheduleDefinition): TaskRunner;
|
||||
@@ -41,10 +53,11 @@ export interface TaskScheduleDefinition {
|
||||
| {
|
||||
cron: string;
|
||||
}
|
||||
| Duration;
|
||||
initialDelay?: Duration;
|
||||
| Duration
|
||||
| HumanDuration;
|
||||
initialDelay?: Duration | HumanDuration;
|
||||
scope?: 'global' | 'local';
|
||||
timeout: Duration;
|
||||
timeout: Duration | HumanDuration;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -177,8 +177,8 @@ describe('PluginTaskManagerImpl', () => {
|
||||
const promise = new Promise(resolve => fn.mockImplementation(resolve));
|
||||
await manager.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: Duration.fromMillis(5000),
|
||||
frequency: Duration.fromMillis(5000),
|
||||
timeout: { milliseconds: 5000 },
|
||||
frequency: { milliseconds: 5000 },
|
||||
fn,
|
||||
scope: 'local',
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Knex } from 'knex';
|
||||
import { Duration } from 'luxon';
|
||||
import { Logger } from 'winston';
|
||||
import { LocalTaskWorker } from './LocalTaskWorker';
|
||||
import { TaskWorker } from './TaskWorker';
|
||||
@@ -48,6 +49,20 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
await TaskWorker.trigger(knex, id);
|
||||
}
|
||||
|
||||
private parseDuration(
|
||||
frequency: TaskScheduleDefinition['frequency'],
|
||||
): string {
|
||||
if ('cron' in frequency) {
|
||||
return frequency.cron;
|
||||
}
|
||||
|
||||
if (frequency instanceof Duration) {
|
||||
return frequency.toISO();
|
||||
}
|
||||
|
||||
return Duration.fromObject(frequency).toISO();
|
||||
}
|
||||
|
||||
async scheduleTask(
|
||||
task: TaskScheduleDefinition & TaskInvocationDefinition,
|
||||
): Promise<void> {
|
||||
@@ -61,12 +76,11 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
await worker.start(
|
||||
{
|
||||
version: 2,
|
||||
cadence:
|
||||
'cron' in task.frequency
|
||||
? task.frequency.cron
|
||||
: task.frequency.toISO(),
|
||||
initialDelayDuration: task.initialDelay?.toISO(),
|
||||
timeoutAfterDuration: task.timeout.toISO(),
|
||||
cadence: this.parseDuration(task.frequency),
|
||||
initialDelayDuration:
|
||||
task.initialDelay && this.parseDuration(task.initialDelay),
|
||||
timeoutAfterDuration:
|
||||
task.timeout && this.parseDuration(task.timeout),
|
||||
},
|
||||
{
|
||||
signal: task.signal,
|
||||
@@ -78,12 +92,11 @@ export class PluginTaskSchedulerImpl implements PluginTaskScheduler {
|
||||
worker.start(
|
||||
{
|
||||
version: 2,
|
||||
cadence:
|
||||
'cron' in task.frequency
|
||||
? task.frequency.cron
|
||||
: task.frequency.toISO(),
|
||||
initialDelayDuration: task.initialDelay?.toISO(),
|
||||
timeoutAfterDuration: task.timeout.toISO(),
|
||||
cadence: this.parseDuration(task.frequency),
|
||||
initialDelayDuration:
|
||||
task.initialDelay && this.parseDuration(task.initialDelay),
|
||||
timeoutAfterDuration:
|
||||
task.timeout && this.parseDuration(task.timeout),
|
||||
},
|
||||
{
|
||||
signal: task.signal,
|
||||
|
||||
@@ -21,4 +21,5 @@ export type {
|
||||
TaskInvocationDefinition,
|
||||
TaskRunner,
|
||||
TaskScheduleDefinition,
|
||||
HumanDuration,
|
||||
} from './types';
|
||||
|
||||
@@ -19,6 +19,21 @@ import { Duration } from 'luxon';
|
||||
import { AbortSignal } from 'node-abort-controller';
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Human friendly durations object
|
||||
* @public
|
||||
*/
|
||||
export type HumanDuration = {
|
||||
years?: number;
|
||||
months?: number;
|
||||
weeks?: number;
|
||||
days?: number;
|
||||
hours?: number;
|
||||
minutes?: number;
|
||||
seconds?: number;
|
||||
milliseconds?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that can be called as a scheduled task.
|
||||
*
|
||||
@@ -74,14 +89,15 @@ export interface TaskScheduleDefinition {
|
||||
*/
|
||||
cron: string;
|
||||
}
|
||||
| Duration;
|
||||
| Duration
|
||||
| HumanDuration;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* is permitted to take place (possibly, then, on a different worker).
|
||||
*/
|
||||
timeout: Duration;
|
||||
timeout: Duration | HumanDuration;
|
||||
|
||||
/**
|
||||
* The amount of time that should pass before the first invocation happens.
|
||||
@@ -100,7 +116,7 @@ export interface TaskScheduleDefinition {
|
||||
* work; its main intended use is for individual machines to get a chance to
|
||||
* reach some equilibrium at startup before triggering heavy batch workloads.
|
||||
*/
|
||||
initialDelay?: Duration;
|
||||
initialDelay?: Duration | HumanDuration;
|
||||
|
||||
/**
|
||||
* Sets the scope of concurrency control / locking to apply for invocations of
|
||||
|
||||
Reference in New Issue
Block a user