@clairejs/server 3.27.2 → 3.27.4

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,8 @@
1
1
  ## Change Log
2
2
 
3
- #### 3.27.2
3
+ #### 3.27.4
4
4
 
5
+ - implement job retry logic
5
6
  - use aws scheduler for jobs
6
7
 
7
8
  #### 3.26.2
@@ -29,11 +29,7 @@ export declare abstract class AbstractJobScheduler {
29
29
  * @param id The job id returned from scheduleJobAt function
30
30
  */
31
31
  protected abstract cancelJob(id: string): Promise<void>;
32
- /**
33
- * Clean up the job after it has been executed
34
- * @param job The job to clean up
35
- */
36
- protected abstract cleanupJob(job: AbstractJob): Promise<void>;
32
+ protected abstract retryJob(payload: AbstractJob): Promise<void>;
37
33
  /**
38
34
  * Remove the scheduled job and prevent if from running in the future
39
35
  * @param id The job id returned from scheduleJobAt function
@@ -129,8 +129,6 @@ export class AbstractJobScheduler {
129
129
  await jobHandler.handlerFn(job);
130
130
  //-- job run success, update
131
131
  update.lastSuccessAt = Date.now();
132
- //-- clean up
133
- await this.cleanupJob(job);
134
132
  //-- reset retry count if this is cron job
135
133
  if (job.cron) {
136
134
  if (job.retryCount) {
@@ -150,7 +148,7 @@ export class AbstractJobScheduler {
150
148
  //-- retry by reschedule the job
151
149
  update.retryCount = (job.retryCount || 0) + 1;
152
150
  const retryDelay = job.retryDelayMs || 0;
153
- await this.scheduleJob({ ...job, at: Date.now() + (retryDelay < 60000 ? 60000 : retryDelay) });
151
+ await this.retryJob({ ...job, ...update, at: Date.now() + (retryDelay < 60000 ? 60000 : retryDelay) });
154
152
  }
155
153
  else {
156
154
  if (job.cron) {
@@ -15,8 +15,10 @@ export declare class AwsJobScheduler extends AbstractJobScheduler {
15
15
  constructor(logger: AbstractLogger, db: AbstractDbAdapter, jobRepo: AbstractJobRepository, apiLambdaFunctionArn: string, apiLambdaFunctionRoleArn: string, jobNamespace: string);
16
16
  handleCron(jobInfo: AbstractJob): Promise<void>;
17
17
  private convertCronToSchedulerExpression;
18
- protected cleanupJob(job: AbstractJob): Promise<void>;
18
+ private getJobName;
19
+ private getOneTimeExpression;
19
20
  protected getScheduledJobs(): Promise<AbstractJob[]>;
21
+ protected retryJob(payload: AbstractJob): Promise<void>;
20
22
  protected _scheduleJob(jobInfo: AbstractJob): Promise<void>;
21
23
  cancelJob(jobId: string): Promise<void>;
22
24
  }
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { AbstractLogger, Errors, LogContext } from "@clairejs/core";
11
11
  import { AbstractDbAdapter } from "@clairejs/orm";
12
- import { SchedulerClient, CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ListSchedulesCommand, ScheduleState } from "@aws-sdk/client-scheduler";
12
+ import { SchedulerClient, CreateScheduleCommand, DeleteScheduleCommand, GetScheduleCommand, ListSchedulesCommand, ScheduleState, ActionAfterCompletion, UpdateScheduleCommand } from "@aws-sdk/client-scheduler";
13
13
  import { AbstractJobScheduler } from "./AbstractJobScheduler";
14
14
  import { AbstractJobRepository } from "./AbstractJobRepository";
15
15
  /**
@@ -56,10 +56,12 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
56
56
  }
57
57
  return parts.join(" ");
58
58
  }
59
- async cleanupJob(job) {
60
- if (job.at) {
61
- await this.cancelJob(job.id);
62
- }
59
+ getJobName(jobId) {
60
+ return `${this.jobNamespace}${jobId}`;
61
+ }
62
+ getOneTimeExpression(at) {
63
+ const date = new Date(at);
64
+ return `at(${date.toISOString().replace(/\.\d{3}Z$/, '')})`;
63
65
  }
64
66
  async getScheduledJobs() {
65
67
  try {
@@ -94,6 +96,28 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
94
96
  return [];
95
97
  }
96
98
  }
99
+ async retryJob(payload) {
100
+ this.logger.debug("Retrying job: ", payload);
101
+ if (payload.at) {
102
+ if (payload.cron) {
103
+ //- retry a cron job
104
+ await this._scheduleJob({ ...payload, id: `${payload.id}-retry-${payload.retryCount}` });
105
+ }
106
+ else {
107
+ //- retry a one-time job, update the schedule
108
+ const jobName = this.getJobName(payload.id);
109
+ const schedule = await this.scheduler.send(new GetScheduleCommand({
110
+ Name: jobName,
111
+ GroupName: schedulerGroupName,
112
+ }));
113
+ const updateCommand = new UpdateScheduleCommand({
114
+ ...schedule,
115
+ ScheduleExpression: this.getOneTimeExpression(payload.at),
116
+ });
117
+ await this.scheduler.send(updateCommand);
118
+ }
119
+ }
120
+ }
97
121
  async _scheduleJob(jobInfo) {
98
122
  this.logger.debug("Scheduling job: ", jobInfo);
99
123
  if (jobInfo.cron || jobInfo.at) {
@@ -101,9 +125,7 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
101
125
  let scheduleExpression;
102
126
  let flexibleTimeWindow;
103
127
  if (jobInfo.at) {
104
- // For one-time jobs, use at() expression
105
- const date = new Date(jobInfo.at);
106
- scheduleExpression = `at(${date.toISOString().replace(/\.\d{3}Z$/, '')})`;
128
+ scheduleExpression = this.getOneTimeExpression(jobInfo.at);
107
129
  // Add flexible time window for one-time jobs to handle slight delays
108
130
  flexibleTimeWindow = {
109
131
  Mode: "OFF",
@@ -141,6 +163,7 @@ let AwsJobScheduler = class AwsJobScheduler extends AbstractJobScheduler {
141
163
  }),
142
164
  },
143
165
  State: ScheduleState.ENABLED,
166
+ ActionAfterCompletion: ActionAfterCompletion.DELETE,
144
167
  };
145
168
  try {
146
169
  const createCommand = new CreateScheduleCommand(scheduleParams);
@@ -50,11 +50,11 @@ export declare class LocalJobScheduler extends AbstractJobScheduler implements I
50
50
  private sendJob;
51
51
  private processMessage;
52
52
  private extendMutexKey;
53
- protected cleanupJob(): Promise<void>;
54
53
  init(): Promise<void>;
55
54
  exit(): void;
56
55
  protected getScheduledJobs(): Promise<AbstractJob[]>;
57
56
  syncJobs(): Promise<void>;
57
+ protected retryJob(payload: AbstractJob): Promise<void>;
58
58
  protected _scheduleJob(jobInfo: AbstractJob): Promise<void>;
59
59
  protected cancelJob(jobId: string): Promise<void>;
60
60
  }
@@ -103,9 +103,6 @@ let LocalJobScheduler = class LocalJobScheduler extends AbstractJobScheduler {
103
103
  await this.redisClient.setex(this.holdMutexKey, this.keyRetentionDurationSeconds, 1);
104
104
  this.logger.debug("Scheduler extends mutex key");
105
105
  }
106
- async cleanupJob() {
107
- //-- do nothing
108
- }
109
106
  async init() {
110
107
  this.logger.debug("LocalJobScheduler init");
111
108
  //-- subscribe to multi client channel
@@ -157,6 +154,9 @@ let LocalJobScheduler = class LocalJobScheduler extends AbstractJobScheduler {
157
154
  }
158
155
  return;
159
156
  }
157
+ async retryJob(payload) {
158
+ return await this._scheduleJob(payload);
159
+ }
160
160
  async _scheduleJob(jobInfo) {
161
161
  if (this.isActive) {
162
162
  //-- case each job type
@@ -11,7 +11,6 @@ const parseCookie = (cookieArray) => {
11
11
  return result;
12
12
  };
13
13
  export const lambdaRequestMapper = (event) => {
14
- console.log("lambda event", event);
15
14
  if (event.requestContext.eventType) {
16
15
  //-- socket
17
16
  const method = event.requestContext.eventType.toLowerCase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clairejs/server",
3
- "version": "3.27.2",
3
+ "version": "3.27.4",
4
4
  "description": "Claire server NodeJs framework written in Typescript.",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",