@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.
@@ -9,6 +9,84 @@ export const openapi = {
9
9
  bearerFormat: "hex-256",
10
10
  },
11
11
  },
12
+ parameters: {
13
+ JobId: {
14
+ name: "jobId",
15
+ in: "path",
16
+ required: true,
17
+ schema: { type: "string" },
18
+ },
19
+ },
20
+ schemas: {
21
+ Job: {
22
+ type: "object",
23
+ additionalProperties: false,
24
+ properties: {
25
+ id: { type: "string", example: "example-job" },
26
+ cron: { type: "string", minLength: 1, example: "*/5 * * * *" },
27
+ action: {
28
+ type: "string",
29
+ enum: ["exec", "call", "copy", "move", "delete", "archive"],
30
+ example: "copy",
31
+ },
32
+ command: { type: "string" },
33
+ shell: {
34
+ anyOf: [{ type: "boolean" }, { type: "string", minLength: 1 }],
35
+ },
36
+ args: {
37
+ type: "array",
38
+ items: { type: "string", minLength: 1 },
39
+ minItems: 1,
40
+ },
41
+ env: {
42
+ type: "object",
43
+ propertyNames: {
44
+ type: "string",
45
+ pattern: "^[A-Z_][A-Z0-9_]*$",
46
+ },
47
+ additionalProperties: { type: "string" },
48
+ },
49
+ source: {
50
+ type: "object",
51
+ additionalProperties: false,
52
+ properties: {
53
+ dir: { type: "string", minLength: 1 },
54
+ includes: {
55
+ type: "array",
56
+ items: { type: "string", minLength: 1 },
57
+ minItems: 1,
58
+ },
59
+ excludes: {
60
+ type: "array",
61
+ items: { type: "string", minLength: 1 },
62
+ minItems: 1,
63
+ },
64
+ },
65
+ },
66
+ target: {
67
+ type: "object",
68
+ additionalProperties: false,
69
+ properties: {
70
+ dir: { type: "string", minLength: 1 },
71
+ archive_name: { type: "string", minLength: 1 },
72
+ permissions: {
73
+ type: "object",
74
+ additionalProperties: false,
75
+ properties: {
76
+ owner: { type: "string", minLength: 1 },
77
+ file_mode: { type: "string", minLength: 1 },
78
+ dir_mode: { type: "string", minLength: 1 },
79
+ },
80
+ },
81
+ retention: { type: "string", minLength: 1 },
82
+ },
83
+ },
84
+ dry_run: { type: "boolean" },
85
+ verbose: { type: "boolean" },
86
+ enabled: { type: "boolean" },
87
+ },
88
+ },
89
+ },
12
90
  },
13
91
  tags: [
14
92
  {
@@ -17,19 +95,11 @@ export const openapi = {
17
95
  },
18
96
  {
19
97
  name: "jobs",
20
- description: "CronOps job related tasks",
98
+ description: "job related api",
21
99
  },
22
100
  {
23
- name: "admin",
24
- description: "CronOps admin tasks",
25
- },
26
- {
27
- name: "user",
28
- description: "Operations about user",
29
- externalDocs: {
30
- description: "Find out more about our store",
31
- url: "http://swagger.io",
32
- },
101
+ name: "schedule",
102
+ description: "scheduling api",
33
103
  },
34
104
  ],
35
105
  paths: {
@@ -84,18 +154,69 @@ export const openapi = {
84
154
  },
85
155
  },
86
156
  },
87
- "/api/jobs/trigger/{jobId}": {
157
+ "/api/jobs": {
158
+ get: {
159
+ summary: "Get jobs",
160
+ tags: ["jobs"],
161
+ responses: {
162
+ "200": {
163
+ description: "Array of scheduled jobs",
164
+ content: {
165
+ "application/json": {
166
+ schema: {
167
+ type: "array",
168
+ items: { $ref: "#/components/schemas/Job" },
169
+ },
170
+ },
171
+ },
172
+ },
173
+ },
174
+ },
175
+ },
176
+ "/api/jobs/{jobId}": {
177
+ get: {
178
+ summary: "Get a job",
179
+ tags: ["jobs"],
180
+ parameters: [{ $ref: "#/components/parameters/JobId" }],
181
+ responses: {
182
+ "200": {
183
+ description: "Array of scheduled jobs",
184
+ content: {
185
+ "application/json": {
186
+ schema: { $ref: "#/components/schemas/Job" },
187
+ },
188
+ },
189
+ },
190
+ "404": {
191
+ description: "Job not found",
192
+ },
193
+ },
194
+ },
195
+ },
196
+ "/api/status": {
197
+ get: {
198
+ summary: "Get status",
199
+ tags: ["schedule"],
200
+ responses: {
201
+ "200": {
202
+ description: "Array of scheduled jobs",
203
+ content: {
204
+ "application/json": {
205
+ schema: {
206
+ type: "array",
207
+ items: { $ref: "#/components/schemas/Job" },
208
+ },
209
+ },
210
+ },
211
+ },
212
+ },
213
+ },
214
+ },
215
+ "/api/trigger/{jobId}": {
88
216
  post: {
89
217
  summary: "Trigger a job",
90
- tags: ["jobs"],
91
- parameters: [
92
- {
93
- name: "jobId",
94
- in: "path",
95
- required: true,
96
- schema: { type: "string" },
97
- },
98
- ],
218
+ tags: ["schedule"],
219
+ parameters: [{ $ref: "#/components/parameters/JobId" }],
99
220
  responses: {
100
221
  "200": {
101
222
  description: "Triggered",
@@ -118,18 +239,10 @@ export const openapi = {
118
239
  },
119
240
  },
120
241
  },
121
- "/api/jobs/pause/{jobId}": {
242
+ "/api/pause": {
122
243
  post: {
123
- summary: "Pause a job",
124
- tags: ["jobs"],
125
- parameters: [
126
- {
127
- name: "jobId",
128
- in: "path",
129
- required: true,
130
- schema: { type: "string" },
131
- },
132
- ],
244
+ summary: "Pause jobs",
245
+ tags: ["schedule"],
133
246
  responses: {
134
247
  "200": {
135
248
  description: "Paused",
@@ -139,7 +252,7 @@ export const openapi = {
139
252
  type: "object",
140
253
  properties: {
141
254
  paused: { type: "boolean", example: true },
142
- jobId: { type: "string", example: "job-123" },
255
+ jobs: { type: "number", example: 4 },
143
256
  },
144
257
  },
145
258
  },
@@ -148,27 +261,20 @@ export const openapi = {
148
261
  },
149
262
  },
150
263
  },
151
- "/api/jobs/resume/{jobId}": {
264
+ "/api/pause/job/{jobId}": {
152
265
  post: {
153
- summary: "Resume a job",
154
- tags: ["jobs"],
155
- parameters: [
156
- {
157
- name: "jobId",
158
- in: "path",
159
- required: true,
160
- schema: { type: "string" },
161
- },
162
- ],
266
+ summary: "Pause a job",
267
+ tags: ["schedule"],
268
+ parameters: [{ $ref: "#/components/parameters/JobId" }],
163
269
  responses: {
164
270
  "200": {
165
- description: "Resumed",
271
+ description: "Paused",
166
272
  content: {
167
273
  "application/json": {
168
274
  schema: {
169
275
  type: "object",
170
276
  properties: {
171
- resumed: { type: "boolean", example: true },
277
+ paused: { type: "boolean", example: true },
172
278
  jobId: { type: "string", example: "job-123" },
173
279
  },
174
280
  },
@@ -178,20 +284,21 @@ export const openapi = {
178
284
  },
179
285
  },
180
286
  },
181
- "/api/jobs/pause/": {
287
+ "/api/resume/job/{jobId}": {
182
288
  post: {
183
- summary: "Pause all jobs",
184
- tags: ["jobs"],
289
+ summary: "Resume a paused job",
290
+ tags: ["schedule"],
291
+ parameters: [{ $ref: "#/components/parameters/JobId" }],
185
292
  responses: {
186
293
  "200": {
187
- description: "Paused",
294
+ description: "Resumed",
188
295
  content: {
189
296
  "application/json": {
190
297
  schema: {
191
298
  type: "object",
192
299
  properties: {
193
- paused: { type: "boolean", example: true },
194
- jobs: { type: "number", example: 4 },
300
+ resumed: { type: "boolean", example: true },
301
+ jobId: { type: "string", example: "job-123" },
195
302
  },
196
303
  },
197
304
  },
@@ -200,10 +307,10 @@ export const openapi = {
200
307
  },
201
308
  },
202
309
  },
203
- "/api/jobs/resume/": {
310
+ "/api/resume": {
204
311
  post: {
205
- summary: "Resume all jobs",
206
- tags: ["jobs"],
312
+ summary: "Resume paused jobs",
313
+ tags: ["schedule"],
207
314
  responses: {
208
315
  "200": {
209
316
  description: "Resumed",
@@ -5,7 +5,7 @@ import { openapi } from "./openapi.js";
5
5
  const app = Fastify();
6
6
  const port = Number(process.env[ENV.PORT] ?? 8118);
7
7
  const host = process.env[ENV.HOST] ?? "127.0.0.1";
8
- const baseUrl = process.env[ENV.BASE_URL] ?? "http://127.0.0.1:8118";
8
+ const baseUrl = process.env[ENV.BASE_URL] ?? `http://127.0.0.1:${port}`;
9
9
  const apiKey = process.env[ENV.API_KEY];
10
10
  app.addHook("preHandler", async (request, reply) => {
11
11
  if (request.method === "OPTIONS" || !request.url.startsWith("/api"))
@@ -38,7 +38,33 @@ app.get("/health", async (request, reply) => {
38
38
  const jobs = jobScheduler.getScheduledJobs();
39
39
  reply.code(200).send({ status: "ok", active_jobs: jobs.length });
40
40
  });
41
- app.post("/api/jobs/trigger/:jobId", async (request, reply) => {
41
+ app.get("/api/jobs", async (request) => {
42
+ const jobScheduler = request.server.scheduler;
43
+ return jobScheduler.getScheduledJobs();
44
+ });
45
+ app.get("/api/jobs/:jobId", async (request, reply) => {
46
+ const { jobId } = request.params;
47
+ const jobScheduler = request.server.scheduler;
48
+ if (!jobScheduler.isJobScheduled(jobId)) {
49
+ return reply.code(404).send();
50
+ }
51
+ return jobScheduler.getJob(jobId);
52
+ });
53
+ app.get("/api/status", async (request) => {
54
+ const jobScheduler = request.server.scheduler;
55
+ return jobScheduler.getScheduledJobsInfo();
56
+ });
57
+ app.post("/api/pause", async (request) => {
58
+ const jobScheduler = request.server.scheduler;
59
+ await jobScheduler.pauseScheduling();
60
+ return { paused: true };
61
+ });
62
+ app.post("/api/resume", async (request) => {
63
+ const jobScheduler = request.server.scheduler;
64
+ await jobScheduler.resumeScheduling();
65
+ return { resumed: true };
66
+ });
67
+ app.post("/api/trigger/:jobId", async (request, reply) => {
42
68
  const { jobId } = request.params;
43
69
  const jobScheduler = request.server.scheduler;
44
70
  if (!jobScheduler.isJobScheduled(jobId)) {
@@ -141,12 +141,12 @@ export class AbstractHandler {
141
141
  await Promise.all(targetScanPromises);
142
142
  fileHistory.cleanup();
143
143
  }
144
- async setTargetFilePermissions(destPath, perms, isDir = false) {
144
+ async setTargetFilePermissions(destFile, perms, isDir = false) {
145
145
  const mode = isDir ? perms.dirMode : perms.fileMode;
146
146
  if (perms.uid >= 0 && perms.gid >= 0)
147
- await fsx.chown(destPath, perms.uid, perms.gid);
147
+ await fsx.chown(destFile, perms.uid, perms.gid);
148
148
  if (mode >= 0)
149
- await fsx.chmod(destPath, mode);
149
+ await fsx.chmod(destFile, mode);
150
150
  }
151
151
  getFolderPermissionPromises(ctx, dirPath, folderPromises) {
152
152
  if (dirPath.length < ctx.targetDir.length || folderPromises.has(dirPath))
@@ -17,7 +17,6 @@ export class ExecHandler extends AbstractHandler {
17
17
  await super.cleanup(ctx, fileHistory);
18
18
  }
19
19
  async exec(ctx, entry) {
20
- const { targetDir } = ctx;
21
20
  const verbose = ctx.job.verbose === true;
22
21
  await new Promise((resolve, reject) => {
23
22
  const { vars, env } = this.createVars(ctx, entry);
@@ -42,7 +41,6 @@ export class ExecHandler extends AbstractHandler {
42
41
  stdio: ["ignore", verbose ? logFd : "ignore", verbose ? logFd : "ignore"],
43
42
  shell: ctx.job.shell ?? this.setup.shell,
44
43
  env: { ...process.env, ...env },
45
- cwd: targetDir,
46
44
  });
47
45
  pid = child.pid;
48
46
  ctx.writeLog(`◉ Subprocess started (pid:${pid}) ➜ ${cmd} [${args}]`);
@@ -27,14 +27,14 @@ export class JobRunnerSetup {
27
27
  targetRootDirs;
28
28
  handlerMap = new Map();
29
29
  constructor(options = {}) {
30
- this.sourceRoot = resolve(options.sourceRoot ?? process.env[ENV.SOURCE_ROOT] ?? "./");
31
- this.targetRoot = resolve(options.targetRoot ?? process.env[ENV.TARGET_ROOT] ?? "./");
32
- this.source2Root = resolve(options.source2Root ?? process.env[ENV.SOURCE_2_ROOT] ?? "./");
33
- this.target2Root = resolve(options.target2Root ?? process.env[ENV.TARGET_2_ROOT] ?? "./");
34
- this.source3Root = resolve(options.source3Root ?? process.env[ENV.SOURCE_3_ROOT] ?? "./");
35
- this.target3Root = resolve(options.target3Root ?? process.env[ENV.TARGET_3_ROOT] ?? "./");
36
- this.configDir = resolve(options.configDir ?? process.env[ENV.CONFIG_DIR] ?? join(os.homedir(), ".cronops", "config"));
37
- this.logDir = resolve(options.logDir ?? process.env[ENV.LOG_DIR] ?? join(os.homedir(), ".cronops", "logs"));
30
+ this.sourceRoot = resolve(options.sourceRoot ?? process.env[ENV.SOURCE_ROOT] ?? "./data");
31
+ this.targetRoot = resolve(options.targetRoot ?? process.env[ENV.TARGET_ROOT] ?? "./data");
32
+ this.source2Root = resolve(options.source2Root ?? process.env[ENV.SOURCE_2_ROOT] ?? "./data");
33
+ this.target2Root = resolve(options.target2Root ?? process.env[ENV.TARGET_2_ROOT] ?? "./data");
34
+ this.source3Root = resolve(options.source3Root ?? process.env[ENV.SOURCE_3_ROOT] ?? "./data");
35
+ this.target3Root = resolve(options.target3Root ?? process.env[ENV.TARGET_3_ROOT] ?? "./data");
36
+ this.configDir = resolve(options.configDir ?? process.env[ENV.CONFIG_DIR] ?? "./config");
37
+ this.logDir = resolve(options.logDir ?? process.env[ENV.LOG_DIR] ?? "./logs");
38
38
  this.tempDir = resolve(options.tempDir ?? process.env[ENV.TEMP_DIR] ?? join(os.tmpdir(), "cronops"));
39
39
  this.uid = options.uid ?? process.env[ENV.PUID] ?? `${process.getuid?.() ?? "0"}`;
40
40
  this.gid = options.gid ?? process.env[ENV.PGID] ?? `${process.getgid?.() ?? "0"}`;
package/dist/server.js CHANGED
@@ -34,18 +34,25 @@ export async function start() {
34
34
  console.log(`🔴 Error loading job '${entry}'. ${message}`);
35
35
  });
36
36
  jobLoader.onJobLoaded((job) => {
37
- if (job.enabled !== false)
38
- jobScheduler.scheduleJob(job);
37
+ jobScheduler.scheduleJob(job);
39
38
  });
40
39
  jobLoader.onJobDeleted((jobId) => {
41
40
  jobScheduler.unscheduleJob(jobId);
42
41
  });
43
42
  jobScheduler.onChanged((isReload) => {
44
- const jobs = jobScheduler.getScheduledJobs();
45
- console.log(`\nJob config ${isReload ? "changed" : "loaded"} (${plural(jobs.length, "active job")})`);
43
+ const jobs = jobScheduler.getScheduledJobsInfo();
44
+ console.log(`\nJob config ${isReload ? "changed" : "loaded"}`);
46
45
  for (const job of jobs) {
47
- console.log(` 🕔 [${job.id}] scheduled (${chalk.greenBright(job.cron)})${job.dry_run ? " 👋 DRY-RUN mode!" : ""}`);
46
+ if (job.status !== "paused")
47
+ console.log(` 🕔 [${job.id}] scheduled (${chalk.greenBright(job.cron)})${job.dry_run ? " 👋 DRY-RUN mode!" : ""}`);
48
48
  }
49
+ for (const job of jobs) {
50
+ if (job.status === "paused")
51
+ console.log(` ⚫ [${job.id}] inactive`);
52
+ }
53
+ });
54
+ jobScheduler.onJobExecute((job) => {
55
+ console.error(`[${job.id}] triggered manually`);
49
56
  });
50
57
  jobScheduler.onJobError((job, err) => {
51
58
  console.error(chalk.red(`[${job.id}] ERROR ${err.message}`));
@@ -1,17 +1,26 @@
1
1
  import { type ScheduledTask } from "node-cron";
2
2
  import { EventEmitter } from "node:events";
3
- import type { Task } from "../types/Task.types.js";
3
+ import type { Task, TaskInfo } from "../types/Task.types.js";
4
4
  export declare abstract class AbstractTask<T> implements Task {
5
5
  protected cronTask: ScheduledTask;
6
6
  protected events: EventEmitter<any>;
7
7
  protected errorCount: number;
8
+ private runCount;
9
+ private isScheduled;
8
10
  private isRunning;
11
+ private isPaused;
12
+ private lastRun?;
13
+ private lastDuration?;
9
14
  constructor(cronStr?: string);
10
15
  protected abstract run(): Promise<T>;
11
16
  schedule(runImmediately?: boolean): void;
12
17
  unschedule(): void;
13
- execute(cb?: (result: T) => void): void;
18
+ pause(): void;
19
+ resume(): void;
20
+ getInfo(): TaskInfo;
21
+ execute<T>(): Promise<T>;
14
22
  onScheduled(cb: () => void): void;
23
+ onExecute(cb: () => void): void;
15
24
  onStarted(cb: () => void): void;
16
25
  onFinished<T>(cb: (result: T) => void): void;
17
26
  onError(cb: (error: Error) => void): void;
@@ -1,4 +1,4 @@
1
- import cron, {} from "node-cron";
1
+ import cron from "node-cron";
2
2
  import { setTimeout } from "node:timers/promises";
3
3
  import { EventEmitter } from "node:events";
4
4
  import { ENV } from "../types/Options.types.js";
@@ -6,20 +6,29 @@ export class AbstractTask {
6
6
  cronTask;
7
7
  events = new EventEmitter();
8
8
  errorCount = 0;
9
+ runCount = 0;
10
+ isScheduled = false;
9
11
  isRunning = false;
12
+ isPaused = false;
13
+ lastRun;
14
+ lastDuration;
10
15
  constructor(cronStr = "* * * * *") {
11
16
  const asyncRunner = async () => {
12
- if (!this.isRunning) {
17
+ if (!this.isRunning && !this.isPaused) {
18
+ this.runCount++;
13
19
  this.isRunning = true;
20
+ this.lastRun = Date.now();
14
21
  try {
15
22
  this.events.emit("started");
16
23
  this.events.emit("finished", await this.run());
17
24
  }
18
25
  catch (err) {
26
+ this.errorCount++;
19
27
  this.events.emit("error", err instanceof Error ? err : new Error(String(err)));
20
28
  }
21
29
  finally {
22
30
  this.isRunning = false;
31
+ this.lastDuration = Date.now() - this.lastRun;
23
32
  }
24
33
  }
25
34
  };
@@ -30,26 +39,45 @@ export class AbstractTask {
30
39
  }
31
40
  schedule(runImmediately = false) {
32
41
  if (runImmediately)
33
- this.cronTask.once("task:started", () => this.execute());
42
+ this.cronTask.once("task:started", () => this.cronTask.execute());
34
43
  this.cronTask.start();
44
+ this.isScheduled = true;
35
45
  }
36
46
  unschedule() {
37
47
  this.events.removeAllListeners();
38
48
  this.cronTask.destroy();
49
+ this.isScheduled = false;
39
50
  }
40
- execute(cb) {
51
+ pause() {
52
+ this.isPaused = true;
53
+ }
54
+ resume() {
55
+ this.isPaused = false;
56
+ }
57
+ getInfo() {
58
+ return {
59
+ status: this.isRunning ? "running" : this.isPaused ? "paused" : this.isScheduled ? "scheduled" : "unscheduled",
60
+ runCount: this.runCount,
61
+ errorCount: this.errorCount,
62
+ lastRun: this.lastRun,
63
+ lastDuration: this.lastDuration,
64
+ };
65
+ }
66
+ execute() {
41
67
  const status = this.cronTask.getStatus();
42
68
  if (status === "destroyed")
43
69
  throw new Error("Invalid task state (destroyed)");
44
70
  if (status === "running" || this.isRunning)
45
71
  throw new Error("Invalid task state (running)");
46
- if (cb)
47
- this.events.once("finished", cb);
48
- this.cronTask.execute();
72
+ this.events.emit("execute");
73
+ return this.cronTask.execute();
49
74
  }
50
75
  onScheduled(cb) {
51
76
  this.cronTask.on("task:started", cb);
52
77
  }
78
+ onExecute(cb) {
79
+ this.events.on("execute", cb);
80
+ }
53
81
  onStarted(cb) {
54
82
  this.events.on("started", cb);
55
83
  }
@@ -57,7 +85,6 @@ export class AbstractTask {
57
85
  this.events.on("finished", cb);
58
86
  }
59
87
  onError(cb) {
60
- this.errorCount++;
61
88
  this.events.on("error", (error) => cb(error));
62
89
  }
63
90
  async gracefulTerminate(timeout = 500) {
@@ -1,5 +1,4 @@
1
1
  import { AbstractTask } from "./AbstractTask.js";
2
- import { JobRunnerResult } from "../models/JobRunnerResult.js";
3
2
  import type { JobModel } from "../models/JobModel.js";
4
3
  import type { JobRunnerSetup } from "../models/JobRunnerSetup.js";
5
4
  import type { RunnerResult, FileHistory } from "../types/Task.types.js";
@@ -9,8 +8,8 @@ export declare class JobRunner extends AbstractTask<RunnerResult> {
9
8
  setup: JobRunnerSetup;
10
9
  constructor(job: JobModel, setup: JobRunnerSetup);
11
10
  onActivity(cb: (action: string, path: string, count: number) => void): void;
12
- runJob(): Promise<JobRunnerResult>;
13
- protected run(): Promise<JobRunnerResult>;
11
+ runJob(): Promise<RunnerResult>;
12
+ protected run(): Promise<RunnerResult>;
14
13
  protected loadFileHistory(job: Job): Promise<FileHistory>;
15
14
  protected saveFileHistory(job: Job, fileHistory: FileHistory): Promise<void>;
16
15
  protected initLog(job: Job): number;
@@ -4,7 +4,6 @@ import { ensureDir, moveSync, readJSON, writeJSON } from "fs-extra/esm";
4
4
  import { AbstractTask } from "./AbstractTask.js";
5
5
  import { JobRunnerContext } from "../models/JobRunnerContext.js";
6
6
  import { closeSync, fsyncSync, openSync, writeSync } from "node:fs";
7
- import { JobRunnerResult } from "../models/JobRunnerResult.js";
8
7
  import { FileHistoryModel } from "../models/FileHistoryModel.js";
9
8
  export class JobRunner extends AbstractTask {
10
9
  job;
@@ -22,10 +21,8 @@ export class JobRunner extends AbstractTask {
22
21
  }
23
22
  async run() {
24
23
  const { setup, job, events } = this;
25
- if (job.enabled === false)
26
- return new JobRunnerResult();
27
- if (this.errorCount >= 25) {
28
- job.enabled = false;
24
+ if (this.errorCount >= 31) {
25
+ this.pause();
29
26
  throw new Error("Too many errors. Job execution disabled!");
30
27
  }
31
28
  await ensureDir(setup.logDir);
@@ -2,8 +2,9 @@ import { JobRunner } from "./JobRunner.js";
2
2
  import { JobRunnerSetup } from "../models/JobRunnerSetup.js";
3
3
  import { AbstractTask } from "./AbstractTask.js";
4
4
  import type { Job } from "../types/Config.types.js";
5
- import type { RunnerResult } from "../types/Task.types.js";
5
+ import type { RunnerResult, TaskInfo } from "../types/Task.types.js";
6
6
  import type { RunnerOptions } from "../types/Options.types.js";
7
+ type SchedulingInfo = Job & TaskInfo;
7
8
  export declare class JobScheduler extends AbstractTask<void> {
8
9
  protected runnerSetup: JobRunnerSetup;
9
10
  protected runnerMap: Map<string, JobRunner>;
@@ -13,19 +14,29 @@ export declare class JobScheduler extends AbstractTask<void> {
13
14
  get scheduledJobs(): number;
14
15
  get tempDir(): string;
15
16
  protected run(): Promise<void>;
17
+ pauseAll(): void;
18
+ resumeAll(): void;
16
19
  unscheduleAll(): void;
17
20
  scheduleJobs(jobs: Job[], cb?: (count: number) => void): void;
18
- scheduleJob(job: Job, defaults?: {}): void;
21
+ scheduleJob(job: Job): void;
19
22
  unscheduleJob(jobId: string): void;
20
23
  isJobScheduled(jobId: string): boolean;
24
+ getJob(jobId: string): Job | undefined;
21
25
  executeJob(jobId: string): void;
22
26
  validateJob(job: Job): void;
27
+ pauseScheduling(): void;
28
+ resumeScheduling(): void;
29
+ pauseJobScheduling(jobId: string): void;
30
+ resumeJobScheduling(jobId: string): void;
23
31
  getScheduledJobs(): Job[];
32
+ getScheduledJobsInfo(): SchedulingInfo[];
24
33
  gracefulTerminate(timeout?: number): Promise<void>;
25
34
  onChanged(cb: (initialConfig: boolean) => void): void;
26
35
  onJobScheduled(cb: (job: Job, rescheduled: boolean) => void): void;
36
+ onJobExecute(cb: (job: Job) => void): void;
27
37
  onJobStarted(cb: (job: Job) => void): void;
28
38
  onJobFinished(cb: (job: Job, stat: RunnerResult) => void): void;
29
39
  onJobActivity(cb: (job: Job, activity: string, path: string, count: number) => void): void;
30
40
  onJobError(cb: (job: Job, err: Error) => void): void;
31
41
  }
42
+ export {};