@clairejs/server 3.23.4 → 3.23.6

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 CHANGED
@@ -1,7 +1,9 @@
1
1
  ## Change Log
2
2
 
3
- #### 3.23.4
3
+ #### 3.23.6
4
4
 
5
+ - fix execCount not being calculated correctly
6
+ - handle syncJobs being called multiple times
5
7
  - fix abstract job scheduler & job model
6
8
  - remove jobId fallback and update schedule job logic
7
9
  - fix fallback jobId by id in AbstractJob
@@ -13,10 +13,11 @@ export declare abstract class AbstractJobScheduler {
13
13
  private _jobs;
14
14
  constructor(logger: AbstractLogger, db: ITransactionFactory, jobRepo: AbstractJobRepository);
15
15
  protected getCurrentJobHandlers(): Promise<JobHandlerMetadata[]>;
16
+ protected abstract getScheduledJobs(): Promise<AbstractJob[]>;
16
17
  /**
17
18
  * Sync all jobs to running state. This should be called only at init time.
18
19
  */
19
- abstract syncJobs(): Promise<void>;
20
+ syncJobs(): Promise<void>;
20
21
  /**
21
22
  * Return unique job id which can then be used to cancel the job
22
23
  * @param payload the necessary info to launch the job
@@ -22,6 +22,53 @@ export class AbstractJobScheduler {
22
22
  }
23
23
  return this._jobs;
24
24
  }
25
+ /**
26
+ * Sync all jobs to running state. This should be called only at init time.
27
+ */
28
+ async syncJobs() {
29
+ //-- check jobs
30
+ const scheduledJobs = await this.getScheduledJobs();
31
+ const allHandlers = await this.getCurrentJobHandlers();
32
+ const tx = await this.db.createTransaction();
33
+ //-- remove job that no more exist
34
+ const nomoreExistJobs = scheduledJobs.filter((job) => !allHandlers.find((handler) => handler.jobName === job.jobName));
35
+ for (const job of nomoreExistJobs) {
36
+ this.logger.info(`Removing stale job: ${job.jobName} of id: ${job.id}`);
37
+ await this.disableJob(job.id, tx);
38
+ }
39
+ if (nomoreExistJobs.length) {
40
+ this.logger.info(`Cleaned up: ${nomoreExistJobs.length} stale jobs`);
41
+ }
42
+ //-- remove scheduled cron jobs that diff the cron expression
43
+ this.logger.debug("Remove scheduled cron jobs");
44
+ const scheduledCronJobs = scheduledJobs.filter((j) => j.cron);
45
+ const updatedScheduledCronJobs = scheduledCronJobs.filter((j) => j.cron && allHandlers.some((job) => job.jobName === j.jobName && job.cron !== j.cron));
46
+ for (const job of updatedScheduledCronJobs) {
47
+ await this.disableJob(job.id, tx);
48
+ }
49
+ await tx.commit();
50
+ //-- reschedule new cron jobs and those which are not synced
51
+ const resyncCronJobs = allHandlers.filter((job) => job.cron &&
52
+ (updatedScheduledCronJobs.some((j) => j.jobName === job.jobName) ||
53
+ !scheduledCronJobs.some((j) => j.jobName === job.jobName)));
54
+ this.logger.debug(`Resync ${resyncCronJobs.length} cron jobs`, resyncCronJobs);
55
+ const allPersistedJobs = await this.jobRepo.getJobs({ _neq: { disabled: true } });
56
+ for (const job of resyncCronJobs) {
57
+ const matchedPersistedJob = allPersistedJobs.find((persistedJob) => persistedJob.jobName === job.jobName && persistedJob.cron === job.cron);
58
+ await this.scheduleJob({
59
+ ...matchedPersistedJob,
60
+ ...job.retryOptions,
61
+ jobName: job.jobName,
62
+ cron: job.cron,
63
+ at: job.at,
64
+ });
65
+ }
66
+ //-- sync "at" jobs
67
+ const missingScheduledAtJobs = allPersistedJobs.filter((job) => job.at && !scheduledJobs.find((scheduled) => scheduled.id === job.id));
68
+ for (const job of missingScheduledAtJobs) {
69
+ await this.scheduleJob(job);
70
+ }
71
+ }
25
72
  async scheduleJob({ id, ...payload }) {
26
73
  let jobId = id;
27
74
  const tx = await this.db.createTransaction();
@@ -115,6 +162,7 @@ export class AbstractJobScheduler {
115
162
  }
116
163
  }
117
164
  await this.jobRepo.updateJobById(job.id, update, tx);
165
+ Object.assign(job, update);
118
166
  }
119
167
  await tx.commit();
120
168
  }
@@ -19,8 +19,7 @@ export declare class AwsJobScheduler extends AbstractJobScheduler {
19
19
  constructor(logger: AbstractLogger, db: AbstractDbAdapter, jobRepo: AbstractJobRepository, apiLambdaFunctionArn: string, jobNamespace: string, eventBusName?: string);
20
20
  handleCron(jobInfo: AbstractJob): Promise<void>;
21
21
  private generateCronFromTimestamp;
22
- getAllScheduledJobs(): Promise<AbstractJob[]>;
22
+ protected getScheduledJobs(): Promise<AbstractJob[]>;
23
23
  protected _scheduleJob(jobInfo: AbstractJob): Promise<void>;
24
- syncJobs(): Promise<void>;
25
24
  cancelJob(jobId: string): Promise<void>;
26
25
  }
@@ -49,7 +49,7 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
49
49
  date.getUTCFullYear(),
50
50
  ].join(" ");
51
51
  }
52
- async getAllScheduledJobs() {
52
+ async getScheduledJobs() {
53
53
  const allRules = await this.eventbridge
54
54
  .listRules({
55
55
  EventBusName: this.eventBusName,
@@ -125,39 +125,6 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
125
125
  throw Errors.SYSTEM_ERROR(`Job does not have time config: ${jobInfo.jobName}`);
126
126
  }
127
127
  }
128
- async syncJobs() {
129
- //-- check jobs
130
- const scheduledJobs = await this.getAllScheduledJobs();
131
- const allHandlers = await this.getCurrentJobHandlers();
132
- //-- remove job that no more exist
133
- const nomoreExistJobs = scheduledJobs.filter((job) => !allHandlers.find((handler) => handler.jobName === job.jobName));
134
- for (const job of nomoreExistJobs) {
135
- this.logger.info(`Removing stale job: ${job.jobName} of id: ${job.id}`);
136
- await this.disableJob(job.id);
137
- }
138
- if (nomoreExistJobs.length) {
139
- this.logger.info(`Cleaned up: ${nomoreExistJobs.length} stale jobs`);
140
- }
141
- //-- remove scheduled cron jobs that diff the cron expression
142
- this.logger.debug("Remove scheduled cron jobs");
143
- const scheduledCronJobs = scheduledJobs.filter((j) => j.cron);
144
- const unmatchedCronJobs = scheduledCronJobs.filter((j) => j.cron && !allHandlers.find((job) => job.jobName === j.jobName && job.cron === j.cron));
145
- if (unmatchedCronJobs.length) {
146
- await Promise.all(unmatchedCronJobs.map((j) => this.disableJob(j.id)));
147
- }
148
- //-- reschedule new cron jobs and those which are not synced
149
- const resyncCronJobs = allHandlers.filter((job) => job.cron &&
150
- (unmatchedCronJobs.some((j) => j.jobName === job.jobName) ||
151
- !scheduledCronJobs.some((j) => j.jobName === job.jobName)));
152
- this.logger.debug("Reschedule cron jobs", resyncCronJobs);
153
- for (const job of resyncCronJobs) {
154
- await this.scheduleJob({
155
- jobName: job.jobName,
156
- cron: job.cron,
157
- });
158
- }
159
- //-- keep "at" jobs as is
160
- }
161
128
  async cancelJob(jobId) {
162
129
  await this.eventbridge
163
130
  .removeTargets({
@@ -52,6 +52,7 @@ export declare class LocalJobScheduler extends AbstractJobScheduler implements I
52
52
  private extendMutexKey;
53
53
  init(): Promise<void>;
54
54
  exit(): void;
55
+ protected getScheduledJobs(): Promise<AbstractJob[]>;
55
56
  syncJobs(): Promise<void>;
56
57
  protected _scheduleJob(jobInfo: AbstractJob): Promise<void>;
57
58
  protected cancelJob(jobId: string): Promise<void>;
@@ -142,25 +142,12 @@ let LocalJobScheduler = class LocalJobScheduler extends AbstractJobScheduler {
142
142
  }
143
143
  this.logger.debug("LocalJobScheduler exit");
144
144
  }
145
+ async getScheduledJobs() {
146
+ return Object.values(this.jobHolder).flatMap((job) => (job?.jobInfo ? [job.jobInfo] : []));
147
+ }
145
148
  async syncJobs() {
146
149
  if (this.isActive) {
147
- //-- schedule all cron & interval jobs
148
- const allJobs = await this.getCurrentJobHandlers();
149
- for (const job of allJobs) {
150
- if (job.cron) {
151
- await this.scheduleJob({
152
- ...job.retryOptions,
153
- jobName: job.jobName,
154
- cron: job.cron,
155
- });
156
- }
157
- }
158
- //-- re-schedule "at" jobs that are stored in repo
159
- const allPersistedJobs = await this.jobRepo.getJobs({ _neq: { disabled: true, at: undefined } });
160
- //-- run job anyway, expired job will be removed then
161
- for (const job of allPersistedJobs) {
162
- await this.scheduleJob(job);
163
- }
150
+ await super.syncJobs();
164
151
  }
165
152
  else {
166
153
  this.sendJob(CommunicationMessage.SYNC_JOB);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clairejs/server",
3
- "version": "3.23.4",
3
+ "version": "3.23.6",
4
4
  "description": "Claire server NodeJs framework written in Typescript.",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",