backend-tasks: Introduce human friendly scheduling

Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2022-05-03 11:33:58 +02:00
parent b6aa189b4d
commit 42a5d99dae
5 changed files with 63 additions and 20 deletions
+16 -3
View File
@@ -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 -3
View File
@@ -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