feat(application): cron job in application (#2730)
This commit is contained in:
parent
ae988d00b0
commit
ce879d2dda
@ -44,7 +44,8 @@
|
||||
"semver": "^7.3.7",
|
||||
"serve-handler": "^6.1.5",
|
||||
"ws": "^8.13.0",
|
||||
"xpipe": "^1.0.5"
|
||||
"xpipe": "^1.0.5",
|
||||
"cron": "^2.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "^7.3.9",
|
||||
|
58
packages/core/server/src/__tests__/cron.test.ts
Normal file
58
packages/core/server/src/__tests__/cron.test.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { mockServer, MockServer, waitSecond } from '@nocobase/test';
|
||||
import { CronJobManager } from '../cron/cron-job-manager';
|
||||
|
||||
describe('cron service', () => {
|
||||
let app: MockServer;
|
||||
beforeEach(async () => {
|
||||
app = mockServer();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.destroy();
|
||||
});
|
||||
|
||||
it('should get cron job manager', async () => {
|
||||
const cron = app.cronJobManager;
|
||||
expect(cron).toBeInstanceOf(CronJobManager);
|
||||
});
|
||||
|
||||
it('should get new cron instance when app reload', async () => {
|
||||
const cron1 = app.cronJobManager;
|
||||
expect(cron1).toBeDefined();
|
||||
cron1.start();
|
||||
expect(cron1.started).toBeTruthy();
|
||||
await app.reload();
|
||||
expect(cron1.started).toBeFalsy();
|
||||
const cron2 = app.cronJobManager;
|
||||
expect(cron2).toBeDefined();
|
||||
expect(cron1).not.toBe(cron2);
|
||||
});
|
||||
|
||||
it('should add cron job', async () => {
|
||||
const cronManager = app.cronJobManager;
|
||||
const jestFn = jest.fn();
|
||||
cronManager.addJob({
|
||||
cronTime: '* * * * * *',
|
||||
onTick: jestFn,
|
||||
});
|
||||
|
||||
expect(jestFn).not.toBeCalled();
|
||||
|
||||
cronManager.start();
|
||||
await waitSecond(2000);
|
||||
expect(jestFn).toBeCalledTimes(2);
|
||||
});
|
||||
|
||||
it('should remove cron job', async () => {
|
||||
const cronManager = app.cronJobManager;
|
||||
const jestFn = jest.fn();
|
||||
const job = cronManager.addJob({
|
||||
cronTime: '* * * * * *',
|
||||
onTick: jestFn,
|
||||
});
|
||||
|
||||
expect(cronManager.jobs.size).toBe(1);
|
||||
cronManager.removeJob(job);
|
||||
expect(cronManager.jobs.size).toBe(0);
|
||||
});
|
||||
});
|
@ -23,6 +23,8 @@ import { ApplicationVersion } from './helpers/application-version';
|
||||
import { Locale } from './locale';
|
||||
import { Plugin } from './plugin';
|
||||
import { InstallOptions, PluginManager } from './plugin-manager';
|
||||
import { CronJob } from 'cron';
|
||||
import { CronJobManager } from './cron/cron-job-manager';
|
||||
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
@ -141,6 +143,12 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
return this._maintainingMessage;
|
||||
}
|
||||
|
||||
protected _cronJobManager: CronJobManager;
|
||||
|
||||
get cronJobManager() {
|
||||
return this._cronJobManager;
|
||||
}
|
||||
|
||||
protected _db: Database;
|
||||
|
||||
get db() {
|
||||
@ -331,6 +339,8 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
|
||||
this._loaded = false;
|
||||
|
||||
await this.emitAsync('beforeReload', this, options);
|
||||
|
||||
await this.load({
|
||||
...options,
|
||||
reload: true,
|
||||
@ -672,6 +682,8 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
this.plugins = new Map<string, Plugin>();
|
||||
this._acl = createACL();
|
||||
|
||||
this._cronJobManager = new CronJobManager(this);
|
||||
|
||||
this.use(logger.middleware, { tag: 'logger' });
|
||||
|
||||
if (this._db) {
|
||||
|
56
packages/core/server/src/cron/cron-job-manager.ts
Normal file
56
packages/core/server/src/cron/cron-job-manager.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { CronJob, CronJobParameters } from 'cron';
|
||||
import Application from '../application';
|
||||
|
||||
export class CronJobManager {
|
||||
private _jobs: Set<CronJob> = new Set();
|
||||
|
||||
private _started = false;
|
||||
|
||||
constructor(private app: Application) {
|
||||
app.on('beforeStop', async () => {
|
||||
this.stop();
|
||||
});
|
||||
|
||||
app.on('afterStart', async () => {
|
||||
this.start();
|
||||
});
|
||||
|
||||
app.on('beforeReload', async () => {
|
||||
this.stop();
|
||||
});
|
||||
}
|
||||
|
||||
public get started() {
|
||||
return this._started;
|
||||
}
|
||||
|
||||
public get jobs() {
|
||||
return this._jobs;
|
||||
}
|
||||
|
||||
public addJob(options: CronJobParameters) {
|
||||
const cronJob = new CronJob(options);
|
||||
this._jobs.add(cronJob);
|
||||
|
||||
return cronJob;
|
||||
}
|
||||
|
||||
public removeJob(job: CronJob) {
|
||||
job.stop();
|
||||
this._jobs.delete(job);
|
||||
}
|
||||
|
||||
public start() {
|
||||
this._jobs.forEach((job) => {
|
||||
job.start();
|
||||
});
|
||||
this._started = true;
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this._jobs.forEach((job) => {
|
||||
job.stop();
|
||||
});
|
||||
this._started = false;
|
||||
}
|
||||
}
|
@ -11,8 +11,8 @@ export function randomStr() {
|
||||
return Math.random().toString(36).substring(2);
|
||||
}
|
||||
|
||||
export const waitSecond = async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
export const waitSecond = async (timeout = 1000) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, timeout));
|
||||
};
|
||||
|
||||
export const startServerWithRandomPort = async (startServer) => {
|
||||
|
17
yarn.lock
17
yarn.lock
@ -5906,6 +5906,11 @@
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.0.tgz#a61043a62c0a72696c73a0a305c544c96501e006"
|
||||
|
||||
"@types/luxon@~3.3.0":
|
||||
version "3.3.2"
|
||||
resolved "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.2.tgz#f6e3524c2486b949a4db445e85d93c8e9886dfe2"
|
||||
integrity sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ==
|
||||
|
||||
"@types/markdown-it-highlightjs@3.3.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmmirror.com/@types/markdown-it-highlightjs/-/markdown-it-highlightjs-3.3.1.tgz#1e051211e7754ba478449fea7faeab3d177ca892"
|
||||
@ -9433,6 +9438,14 @@ cron@^2.3.1:
|
||||
dependencies:
|
||||
luxon "^3.2.1"
|
||||
|
||||
cron@^2.4.4:
|
||||
version "2.4.4"
|
||||
resolved "https://registry.npmjs.org/cron/-/cron-2.4.4.tgz#988c1757b3f288d1dfcc360ee6d80087448916dc"
|
||||
integrity sha512-MHlPImXJj3K7x7lyUHjtKEOl69CSlTOWxS89jiFgNkzXfvhVjhMz/nc7/EIfN9vgooZp8XTtXJ1FREdmbyXOiQ==
|
||||
dependencies:
|
||||
"@types/luxon" "~3.3.0"
|
||||
luxon "~3.3.0"
|
||||
|
||||
croner@~4.1.92:
|
||||
version "4.1.97"
|
||||
resolved "https://registry.npmmirror.com/croner/-/croner-4.1.97.tgz#6e373dc7bb3026fab2deb0d82685feef20796766"
|
||||
@ -15884,7 +15897,7 @@ luxon@^1.28.0:
|
||||
version "1.28.1"
|
||||
resolved "https://registry.npmmirror.com/luxon/-/luxon-1.28.1.tgz#528cdf3624a54506d710290a2341aa8e6e6c61b0"
|
||||
|
||||
luxon@^3.2.1:
|
||||
luxon@^3.2.1, luxon@~3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.npmmirror.com/luxon/-/luxon-3.3.0.tgz#d73ab5b5d2b49a461c47cedbc7e73309b4805b48"
|
||||
|
||||
@ -19211,7 +19224,7 @@ qrcode.react@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmmirror.com/qrcode.react/-/qrcode.react-3.1.0.tgz#5c91ddc0340f768316fbdb8fff2765134c2aecd8"
|
||||
|
||||
qs@^6.10.1, qs@^6.11.0, qs@^6.4.0, qs@^6.5.2, qs@^6.9.4:
|
||||
qs@^6.10.1, qs@^6.11.0, qs@^6.11.2, qs@^6.4.0, qs@^6.5.2, qs@^6.9.4:
|
||||
version "6.11.2"
|
||||
resolved "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
|
||||
dependencies:
|
||||
|
Loading…
Reference in New Issue
Block a user