@mtakla/cronops 0.1.1-rc6 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -56
- package/config/jobs/example-job.yaml +1 -1
- package/dist/api/openapi.d.ts +217 -41
- package/dist/api/openapi.js +162 -55
- package/dist/api/webapi.js +28 -2
- package/dist/handlers/AbstractHandler.js +3 -3
- package/dist/handlers/ExecHandler.js +0 -2
- package/dist/models/JobRunnerSetup.js +8 -8
- package/dist/server.js +12 -5
- package/dist/tasks/AbstractTask.d.ts +11 -2
- package/dist/tasks/AbstractTask.js +35 -8
- package/dist/tasks/JobRunner.d.ts +2 -3
- package/dist/tasks/JobRunner.js +2 -5
- package/dist/tasks/JobScheduler.d.ts +13 -2
- package/dist/tasks/JobScheduler.js +42 -5
- package/dist/types/Config.types.d.ts +8 -1
- package/dist/types/Config.types.js +1 -1
- package/dist/types/Task.types.d.ts +8 -1
- package/package.json +8 -9
|
@@ -2,7 +2,6 @@ import { JobRunner } from "./JobRunner.js";
|
|
|
2
2
|
import { JobModel } from "../models/JobModel.js";
|
|
3
3
|
import { JobRunnerSetup } from "../models/JobRunnerSetup.js";
|
|
4
4
|
import { AbstractTask } from "./AbstractTask.js";
|
|
5
|
-
import { JobError } from "../errors/JobError.js";
|
|
6
5
|
export class JobScheduler extends AbstractTask {
|
|
7
6
|
runnerSetup;
|
|
8
7
|
runnerMap;
|
|
@@ -26,6 +25,14 @@ export class JobScheduler extends AbstractTask {
|
|
|
26
25
|
this.isReload = true;
|
|
27
26
|
}
|
|
28
27
|
}
|
|
28
|
+
pauseAll() {
|
|
29
|
+
for (const runner of this.runnerMap.values())
|
|
30
|
+
runner.resume();
|
|
31
|
+
}
|
|
32
|
+
resumeAll() {
|
|
33
|
+
for (const runner of this.runnerMap.values())
|
|
34
|
+
runner.resume();
|
|
35
|
+
}
|
|
29
36
|
unscheduleAll() {
|
|
30
37
|
for (const runner of this.runnerMap.values())
|
|
31
38
|
runner.unschedule();
|
|
@@ -39,23 +46,24 @@ export class JobScheduler extends AbstractTask {
|
|
|
39
46
|
if (cb)
|
|
40
47
|
cb(this.runnerMap.size);
|
|
41
48
|
}
|
|
42
|
-
scheduleJob(job
|
|
49
|
+
scheduleJob(job) {
|
|
43
50
|
let rescheduled = false;
|
|
44
|
-
if (job.enabled === false)
|
|
45
|
-
JobError.throw(job.id, `Cannot schedule disabled job [${job.id}]!`);
|
|
46
51
|
this.runnerSetup.validateJob(job);
|
|
47
52
|
if (this.runnerMap.has(job.id)) {
|
|
48
53
|
this.runnerMap.get(job.id)?.unschedule();
|
|
49
54
|
rescheduled = true;
|
|
50
55
|
}
|
|
51
|
-
const task = new JobRunner(new JobModel(job
|
|
56
|
+
const task = new JobRunner(new JobModel(job), this.runnerSetup);
|
|
52
57
|
this.runnerMap.set(job.id, task);
|
|
53
58
|
task.onScheduled(() => this.events.emit("job-scheduled", job, rescheduled));
|
|
59
|
+
task.onExecute(() => this.events.emit("job-execute", job));
|
|
54
60
|
task.onStarted(() => this.events.emit("job-started", job));
|
|
55
61
|
task.onFinished((stat) => this.events.emit("job-finished", job, stat));
|
|
56
62
|
task.onActivity((activity, path, count) => this.events.emit("job-activity", job, activity, path, count));
|
|
57
63
|
task.onError((err) => this.events.emit("job-error", job, err));
|
|
58
64
|
task.schedule();
|
|
65
|
+
if (job.enabled === false)
|
|
66
|
+
task.pause();
|
|
59
67
|
this.changed = true;
|
|
60
68
|
}
|
|
61
69
|
unscheduleJob(jobId) {
|
|
@@ -69,6 +77,9 @@ export class JobScheduler extends AbstractTask {
|
|
|
69
77
|
isJobScheduled(jobId) {
|
|
70
78
|
return this.runnerMap.has(jobId);
|
|
71
79
|
}
|
|
80
|
+
getJob(jobId) {
|
|
81
|
+
return this.runnerMap.get(jobId)?.job;
|
|
82
|
+
}
|
|
72
83
|
executeJob(jobId) {
|
|
73
84
|
if (!this.runnerMap.has(jobId))
|
|
74
85
|
throw new Error(`Unknown job [${jobId}]!`);
|
|
@@ -77,9 +88,32 @@ export class JobScheduler extends AbstractTask {
|
|
|
77
88
|
validateJob(job) {
|
|
78
89
|
this.runnerSetup.validateJob(job);
|
|
79
90
|
}
|
|
91
|
+
pauseScheduling() {
|
|
92
|
+
for (const task of this.runnerMap.values())
|
|
93
|
+
this.pauseJobScheduling(task.job.id);
|
|
94
|
+
this.changed = true;
|
|
95
|
+
}
|
|
96
|
+
resumeScheduling() {
|
|
97
|
+
for (const task of this.runnerMap.values())
|
|
98
|
+
this.resumeJobScheduling(task.job.id);
|
|
99
|
+
this.changed = true;
|
|
100
|
+
}
|
|
101
|
+
pauseJobScheduling(jobId) {
|
|
102
|
+
const task = this.runnerMap.get(jobId);
|
|
103
|
+
if (task)
|
|
104
|
+
task.pause();
|
|
105
|
+
}
|
|
106
|
+
resumeJobScheduling(jobId) {
|
|
107
|
+
const task = this.runnerMap.get(jobId);
|
|
108
|
+
if (task && task.job.enabled !== false)
|
|
109
|
+
task.resume();
|
|
110
|
+
}
|
|
80
111
|
getScheduledJobs() {
|
|
81
112
|
return Array.from(this.runnerMap.values()).map((runner) => runner.job);
|
|
82
113
|
}
|
|
114
|
+
getScheduledJobsInfo() {
|
|
115
|
+
return Array.from(this.runnerMap.values()).map((runner) => Object.assign({}, runner.job, runner.getInfo()));
|
|
116
|
+
}
|
|
83
117
|
async gracefulTerminate(timeout = 1000) {
|
|
84
118
|
const jobRunnerTasks = [...this.runnerMap.values()];
|
|
85
119
|
this.unscheduleAll();
|
|
@@ -93,6 +127,9 @@ export class JobScheduler extends AbstractTask {
|
|
|
93
127
|
onJobScheduled(cb) {
|
|
94
128
|
this.events.on("job-scheduled", cb);
|
|
95
129
|
}
|
|
130
|
+
onJobExecute(cb) {
|
|
131
|
+
this.events.on("job-execute", cb);
|
|
132
|
+
}
|
|
96
133
|
onJobStarted(cb) {
|
|
97
134
|
this.events.on("job-started", cb);
|
|
98
135
|
}
|
|
@@ -2,7 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
export declare const JobSchema: z.ZodObject<{
|
|
3
3
|
id: z.ZodOptional<z.ZodString>;
|
|
4
4
|
cron: z.ZodOptional<z.ZodString>;
|
|
5
|
-
action: z.
|
|
5
|
+
action: z.ZodEnum<{
|
|
6
|
+
copy: "copy";
|
|
7
|
+
delete: "delete";
|
|
8
|
+
exec: "exec";
|
|
9
|
+
call: "call";
|
|
10
|
+
move: "move";
|
|
11
|
+
archive: "archive";
|
|
12
|
+
}>;
|
|
6
13
|
command: z.ZodOptional<z.ZodString>;
|
|
7
14
|
shell: z.ZodOptional<z.ZodUnion<[z.ZodBoolean, z.ZodString]>>;
|
|
8
15
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
export const JobSchema = z.strictObject({
|
|
3
3
|
id: z.string().optional(),
|
|
4
4
|
cron: z.string().min(1).optional(),
|
|
5
|
-
action: z.
|
|
5
|
+
action: z.enum(["exec", "call", "copy", "move", "delete", "archive"]),
|
|
6
6
|
command: z.string().optional(),
|
|
7
7
|
shell: z.boolean().or(z.string().min(1)).optional(),
|
|
8
8
|
args: z.array(z.string().min(1)).min(1).optional(),
|
|
@@ -13,6 +13,13 @@ export type RunnerResult = {
|
|
|
13
13
|
endTime: number;
|
|
14
14
|
durationMs: number;
|
|
15
15
|
};
|
|
16
|
+
export type TaskInfo = {
|
|
17
|
+
status: "unscheduled" | "scheduled" | "running" | "paused";
|
|
18
|
+
runCount: number;
|
|
19
|
+
errorCount: number;
|
|
20
|
+
lastRun: number | undefined;
|
|
21
|
+
lastDuration: number | undefined;
|
|
22
|
+
};
|
|
16
23
|
export type SourceFile = {
|
|
17
24
|
sourceEntry: string;
|
|
18
25
|
sourcePath: string;
|
|
@@ -36,7 +43,7 @@ export type FileHistory = {
|
|
|
36
43
|
export interface Task {
|
|
37
44
|
schedule(runImmediately?: boolean): void;
|
|
38
45
|
unschedule(): void;
|
|
39
|
-
execute(
|
|
46
|
+
execute<T>(): Promise<T>;
|
|
40
47
|
onScheduled(cb: () => void): void;
|
|
41
48
|
onStarted(cb: () => void): void;
|
|
42
49
|
onFinished<T>(cb: (result: T) => void): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtakla/cronops",
|
|
3
|
-
"version": "0.1.1
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Automated cross-container file lifecycle management with cron scheduling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "mtakla@nevereven",
|
|
@@ -66,27 +66,26 @@
|
|
|
66
66
|
"zod": "4.3.6"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@biomejs/biome": "^2.
|
|
69
|
+
"@biomejs/biome": "^2.4.4",
|
|
70
70
|
"@types/fs-extra": "^11.0.4",
|
|
71
|
-
"@types/node": "^25.0
|
|
71
|
+
"@types/node": "^25.3.0",
|
|
72
72
|
"@types/shell-quote": "^1.7.5",
|
|
73
73
|
"@types/tar-fs": "2.0.4",
|
|
74
|
-
"@vitest/coverage-v8": "^4.0.
|
|
75
|
-
"typedoc": "^0.28.
|
|
74
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
75
|
+
"typedoc": "^0.28.17",
|
|
76
76
|
"typescript": "^5.9.3",
|
|
77
|
-
"vitest": "^4.0.
|
|
77
|
+
"vitest": "^4.0.18"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"check": "biome check",
|
|
81
81
|
"check:fix": "biome check --write",
|
|
82
82
|
"test": "vitest run",
|
|
83
|
-
"docs": "typedoc",
|
|
84
83
|
"coverage": "vitest run --coverage",
|
|
85
84
|
"loadtest": "tsc && node ./dist/tests/loadtest.js",
|
|
86
|
-
"
|
|
87
|
-
"dev": "tsc && node ./dist/server.js",
|
|
85
|
+
"docs": "typedoc",
|
|
88
86
|
"build": "tsc",
|
|
89
87
|
"build:types": "tsc --declaration",
|
|
88
|
+
"dev": "tsc --sourceMap --inlineSources && node --env-file=.env.local ./dist/server.js",
|
|
90
89
|
"docker": "docker build --load --target app -t cronops-dev:local .",
|
|
91
90
|
"docker:docs": "docker build --load --target docs -t cronops-docs:local ."
|
|
92
91
|
}
|