1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-11-10 01:19:53 +01:00
unleash.unleash/src/lib/features/scheduler/job-service.ts
Gastón Fournier abe160eb7d
feat: Unleash v7 ESM migration (#9877)
We're migrating to ESM, which will allow us to import the latest
versions of our dependencies.

Co-Authored-By: Christopher Kolstad <chriswk@getunleash.io>
2025-05-14 09:47:12 +02:00

64 lines
2.2 KiB
TypeScript

import type { JobStore } from './job-store.js';
import type { Logger, LogProvider } from '../../logger.js';
import { subMinutes } from 'date-fns';
export class JobService {
private jobStore: JobStore;
private logger: Logger;
constructor(jobStore: JobStore, logProvider: LogProvider) {
this.jobStore = jobStore;
this.logger = logProvider('/services/job-service');
}
/**
* Wraps a function in a job that will guarantee the function is executed
* in a mutually exclusive way in a single instance of the cluster, at most
* once every {@param bucketSizeInMinutes}.
*
* The key identifies the job group: only one job in the group will execute
* at any given time.
*
* Note: buckets begin at the start of the time span
*/
public singleInstance(
key: string,
fn: (range?: { from: Date; to: Date }) => Promise<unknown>,
bucketSizeInMinutes = 5,
): () => Promise<unknown> {
return async () => {
const acquired = await this.jobStore.acquireBucket(
key,
bucketSizeInMinutes,
);
if (acquired) {
const { name, bucket } = acquired;
this.logger.info(
`Acquired job lock for ${name} from >= ${subMinutes(
bucket,
bucketSizeInMinutes,
)} to < ${bucket}`,
);
try {
const range = {
from: subMinutes(bucket, bucketSizeInMinutes),
to: bucket,
};
const response = await fn(range);
await this.jobStore.update(name, bucket, {
stage: 'completed',
finishedAt: new Date(),
});
return response;
} catch (err) {
this.logger.error(`Failed to execute job ${name}`, err);
await this.jobStore.update(name, bucket, {
stage: 'failed',
finishedAt: new Date(),
});
}
}
};
}
}