@alanszp/queue 9.2.4 → 9.2.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.
@@ -0,0 +1,10 @@
1
+ import { BaseError, RenderableContext, RenderableError } from "@alanszp/errors";
2
+ import { JobState } from "bullmq";
3
+ export declare class JobCannotBePromotedError extends BaseError implements RenderableError {
4
+ jobId: string;
5
+ currentJobState: JobState | "unknown";
6
+ constructor(jobId: string, currentJobState: JobState | "unknown");
7
+ code(): string;
8
+ renderMessage(): string;
9
+ context(): RenderableContext;
10
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobCannotBePromotedError = void 0;
4
+ const errors_1 = require("@alanszp/errors");
5
+ class JobCannotBePromotedError extends errors_1.BaseError {
6
+ constructor(jobId, currentJobState) {
7
+ super("JobCannotBePromotedError");
8
+ this.jobId = jobId;
9
+ this.currentJobState = currentJobState;
10
+ }
11
+ code() {
12
+ return "job_cannot_be_promoted_error";
13
+ }
14
+ renderMessage() {
15
+ return "Job not found";
16
+ }
17
+ context() {
18
+ return {
19
+ jobId: this.jobId,
20
+ currentJobState: this.currentJobState,
21
+ };
22
+ }
23
+ }
24
+ exports.JobCannotBePromotedError = JobCannotBePromotedError;
25
+ //# sourceMappingURL=JobCannotBePromotedError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobCannotBePromotedError.js","sourceRoot":"","sources":["../../src/errors/JobCannotBePromotedError.ts"],"names":[],"mappings":";;;AAAA,4CAAgF;AAGhF,MAAa,wBACX,SAAQ,kBAAS;IAOjB,YAAY,KAAa,EAAE,eAAqC;QAC9D,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,CAAC;IAED,IAAI;QACF,OAAO,8BAA8B,CAAC;IACxC,CAAC;IAED,aAAa;QACX,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,eAAe,EAAE,IAAI,CAAC,eAAe;SACtC,CAAC;IACJ,CAAC;CACF;AA5BD,4DA4BC"}
@@ -0,0 +1,8 @@
1
+ import { BaseError, RenderableContext, RenderableError } from "@alanszp/errors";
2
+ export declare class JobNotFoundError extends BaseError implements RenderableError {
3
+ jobId: string;
4
+ constructor(jobId: string);
5
+ code(): string;
6
+ renderMessage(): string;
7
+ context(): RenderableContext;
8
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JobNotFoundError = void 0;
4
+ const errors_1 = require("@alanszp/errors");
5
+ class JobNotFoundError extends errors_1.BaseError {
6
+ constructor(jobId) {
7
+ super("JobNotFoundError");
8
+ this.jobId = jobId;
9
+ }
10
+ code() {
11
+ return "job_not_found_error";
12
+ }
13
+ renderMessage() {
14
+ return "Job not found";
15
+ }
16
+ context() {
17
+ return {
18
+ jobId: this.jobId,
19
+ };
20
+ }
21
+ }
22
+ exports.JobNotFoundError = JobNotFoundError;
23
+ //# sourceMappingURL=JobNotFoundError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobNotFoundError.js","sourceRoot":"","sources":["../../src/errors/JobNotFoundError.ts"],"names":[],"mappings":";;;AAAA,4CAAgF;AAEhF,MAAa,gBAAiB,SAAQ,kBAAS;IAG7C,YAAY,KAAa;QACvB,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,IAAI;QACF,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,aAAa;QACX,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC;IACJ,CAAC;CACF;AArBD,4CAqBC"}
@@ -1,4 +1,4 @@
1
1
  import { Queue } from "./queue";
2
2
  import { JobData, QueueOptions } from "../types";
3
3
  import { SharedContext } from "@alanszp/shared-context";
4
- export declare function createQueue<JobType = JobData>(name: string, getContext: () => SharedContext, queueOptions?: QueueOptions): Queue;
4
+ export declare function createQueue<Data = JobData>(name: string, getContext: () => SharedContext, queueOptions?: QueueOptions): Queue<Data>;
@@ -1,18 +1,27 @@
1
1
  import { Job, JobsOptions } from "bullmq";
2
+ import { ListResult } from "@alanszp/core";
2
3
  import { SharedContext } from "@alanszp/shared-context";
3
- import { ConnectionOptions, JobData, QueueOptions } from "../types";
4
- export declare class Queue<JobType = JobData> {
4
+ import { ConnectionOptions, JobData, JobReturnValue, JobTypeEnum, QueueOptions } from "../types";
5
+ export declare class Queue<Data = JobData, ReturnValue = JobReturnValue> {
5
6
  private _queue;
6
7
  private name;
7
8
  private getSharedContext;
8
9
  constructor(connection: ConnectionOptions, name: string, prefix: string, getSharedContext: () => SharedContext, queueOptions?: QueueOptions);
9
10
  getName(): string;
10
- publishJob(job: JobType, opts?: JobsOptions): Promise<Job<JobType>>;
11
- publishBulkJob(jobDatas: JobType[]): Promise<Job<JobType>[]>;
11
+ publishJob(job: Data, opts?: JobsOptions): Promise<Job<Data, ReturnValue>>;
12
+ publishBulkJob(jobDatas: Data[]): Promise<Job<Data, ReturnValue>[]>;
12
13
  publishBulkJobWithOptions(jobDefinitions: {
13
- jobData: JobType;
14
+ jobData: Data;
14
15
  opts: JobsOptions;
15
- }[]): Promise<void>;
16
+ }[]): Promise<Job<Data, ReturnValue>[]>;
17
+ private pageToStartEnd;
18
+ getJobsAndCountByStatus(statuses: JobTypeEnum[], page?: number, pageSize?: number, ascending?: boolean): Promise<ListResult<Job<Data, ReturnValue>>>;
19
+ getJobCountByStatus(statuses: JobTypeEnum[], page?: number, pageSize?: number): Promise<number>;
20
+ getJobsByStatus(statuses: JobTypeEnum[], page?: number, pageSize?: number, ascending?: boolean): Promise<Job<Data, ReturnValue>[]>;
21
+ deleteJob(jobId: string): Promise<void>;
22
+ getJob(jobId: string): Promise<Job<Data, ReturnValue> | undefined>;
23
+ getJobOrFail(jobId: string): Promise<Job<Data, ReturnValue>>;
24
+ changeDelayToJob(jobId: string, delayMs: number): Promise<void>;
16
25
  close(): Promise<void>;
17
26
  private get queue();
18
27
  }
@@ -12,9 +12,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Queue = void 0;
13
13
  const lodash_1 = require("lodash");
14
14
  const types_1 = require("../types");
15
+ const JobNotFoundError_1 = require("../errors/JobNotFoundError");
16
+ const JobCannotBePromotedError_1 = require("../errors/JobCannotBePromotedError");
15
17
  const BULL_PREFIX = "b";
16
18
  const DEFAULT_COMPLETED_JOB_MAX_AGE_IN_SECONDS = 60 * 60 * 24 * 30;
17
19
  const DEFAULT_COMPLETED_JOB_MAX_COUNT = 500;
20
+ const DEFAULT_FAILED_JOB_MAX_COUNT = 1000;
18
21
  class Queue {
19
22
  constructor(connection, name, prefix, getSharedContext, queueOptions) {
20
23
  this.name = name;
@@ -25,6 +28,9 @@ class Queue {
25
28
  age: DEFAULT_COMPLETED_JOB_MAX_AGE_IN_SECONDS,
26
29
  count: DEFAULT_COMPLETED_JOB_MAX_COUNT,
27
30
  },
31
+ removeOnFail: {
32
+ count: DEFAULT_FAILED_JOB_MAX_COUNT,
33
+ },
28
34
  attempts: 3,
29
35
  backoff: {
30
36
  type: "exponential",
@@ -58,7 +64,67 @@ class Queue {
58
64
  data,
59
65
  opts,
60
66
  }));
61
- yield this.queue.addBulk(jobs);
67
+ return this.queue.addBulk(jobs);
68
+ });
69
+ }
70
+ pageToStartEnd(pageNumber, pageSize) {
71
+ return {
72
+ start: (pageNumber - 1) * pageSize,
73
+ end: pageNumber * pageSize - 1,
74
+ };
75
+ }
76
+ getJobsAndCountByStatus(statuses, page = 1, pageSize = 50, ascending = false) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const { start, end } = this.pageToStartEnd(page, pageSize);
79
+ const [total, elements] = yield Promise.all([
80
+ this.queue.getJobCountByTypes(...statuses),
81
+ this.queue.getJobs(statuses, start, end, ascending),
82
+ ]);
83
+ return {
84
+ total,
85
+ elements,
86
+ page,
87
+ pageSize,
88
+ };
89
+ });
90
+ }
91
+ getJobCountByStatus(statuses, page = 1, pageSize = 50) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ return this.queue.getJobCountByTypes(...statuses);
94
+ });
95
+ }
96
+ getJobsByStatus(statuses, page = 1, pageSize = 50, ascending = false) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const { start, end } = this.pageToStartEnd(page, pageSize);
99
+ return this.queue.getJobs(statuses, start, end, ascending);
100
+ });
101
+ }
102
+ deleteJob(jobId) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ this.queue.remove(jobId);
105
+ });
106
+ }
107
+ getJob(jobId) {
108
+ return __awaiter(this, void 0, void 0, function* () {
109
+ return this.queue.getJob(jobId);
110
+ });
111
+ }
112
+ getJobOrFail(jobId) {
113
+ return __awaiter(this, void 0, void 0, function* () {
114
+ const job = yield this.queue.getJob(jobId);
115
+ if (!job)
116
+ throw new JobNotFoundError_1.JobNotFoundError(jobId);
117
+ return job;
118
+ });
119
+ }
120
+ changeDelayToJob(jobId, delayMs) {
121
+ return __awaiter(this, void 0, void 0, function* () {
122
+ const job = yield this.getJobOrFail(jobId);
123
+ const state = yield job.getState();
124
+ if (state !== types_1.JobStateEnum.DELAYED) {
125
+ throw new JobCannotBePromotedError_1.JobCannotBePromotedError(jobId, state);
126
+ }
127
+ job.changeDelay(delayMs);
62
128
  });
63
129
  }
64
130
  close() {
@@ -1 +1 @@
1
- {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/queue/queue.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mCAA+B;AAG/B,oCAA8E;AAE9E,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,MAAM,wCAAwC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACnE,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAE5C,MAAa,KAAK;IAOhB,YACE,UAA6B,EAC7B,IAAY,EACZ,MAAc,EACd,gBAAqC,EACrC,YAA2B;QAE3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QAEzC,IAAI,CAAC,MAAM,GAAG,IAAI,gBAAQ,CAAU,IAAI,kCACnC,IAAA,cAAK,EACN;YACE,iBAAiB,EAAE;gBACjB,gBAAgB,EAAE;oBAChB,GAAG,EAAE,wCAAwC;oBAC7C,KAAK,EAAE,+BAA+B;iBACvC;gBACD,QAAQ,EAAE,CAAC;gBACX,OAAO,EAAE;oBACP,IAAI,EAAE,aAAa;oBACnB,KAAK,EAAE,IAAI;iBACZ;aACF;YACD,UAAU;SACX,EACD,YAAY,IAAI,EAAE,CACnB,GACE,EAAE,MAAM,EAAE,IAAI,MAAM,KAAK,WAAW,EAAE,EAAE,EAC3C,CAAC;IACL,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEK,UAAU,CAAC,GAAY,EAAE,IAAkB;;YAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,kCAAO,GAAG,KAAE,GAAG,EAAE,GAAG,KAAI,IAAI,CAAC,CAAC;QAC/D,CAAC;KAAA;IAEK,cAAc,CAAC,QAAmB;;YACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;KAAA;IAEK,yBAAyB,CAC7B,cAAyD;;YAEzD,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC5D,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI;gBACJ,IAAI;aACL,CAAC,CAAC,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;KAAA;IAEK,KAAK;;YACT,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC;KAAA;IAED,IAAY,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AA1ED,sBA0EC"}
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/queue/queue.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mCAA2C;AAI3C,oCAQkB;AAClB,iEAA8D;AAC9D,iFAA8E;AAG9E,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB,MAAM,wCAAwC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACnE,MAAM,+BAA+B,GAAG,GAAG,CAAC;AAC5C,MAAM,4BAA4B,GAAG,IAAI,CAAC;AAE1C,MAAa,KAAK;IAOhB,YACE,UAA6B,EAC7B,IAAY,EACZ,MAAc,EACd,gBAAqC,EACrC,YAA2B;QAE3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QAEzC,IAAI,CAAC,MAAM,GAAG,IAAI,gBAAQ,CAAO,IAAI,kCAChC,IAAA,cAAK,EACN;YACE,iBAAiB,EAAE;gBACjB,gBAAgB,EAAE;oBAChB,GAAG,EAAE,wCAAwC;oBAC7C,KAAK,EAAE,+BAA+B;iBACvC;gBACD,YAAY,EAAE;oBACZ,KAAK,EAAE,4BAA4B;iBACpC;gBACD,QAAQ,EAAE,CAAC;gBACX,OAAO,EAAE;oBACP,IAAI,EAAE,aAAa;oBACnB,KAAK,EAAE,IAAI;iBACZ;aACF;YACD,UAAU;SACX,EACD,YAAY,IAAI,EAAE,CACnB,GACE,EAAE,MAAM,EAAE,IAAI,MAAM,KAAK,WAAW,EAAE,EAAE,EAC3C,CAAC;IACL,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEK,UAAU,CACd,GAAS,EACT,IAAkB;;YAElB,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxC,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,kCAAO,GAAG,KAAE,GAAG,EAAE,GAAG,KAAI,IAAI,CAAC,CAAC;QAC/D,CAAC;KAAA;IAEK,cAAc,CAAC,QAAgB;;YACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;KAAA;IAEK,yBAAyB,CAC7B,cAAsD;;YAEtD,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC5D,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI;gBACJ,IAAI;aACL,CAAC,CAAC,CAAC;YACJ,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;KAAA;IAEO,cAAc,CAAC,UAAkB,EAAE,QAAgB;QACzD,OAAO;YACL,KAAK,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,QAAQ;YAClC,GAAG,EAAE,UAAU,GAAG,QAAQ,GAAG,CAAC;SAC/B,CAAC;IACJ,CAAC;IAEY,uBAAuB,CAClC,QAAuB,EACvB,OAAe,CAAC,EAChB,WAAmB,EAAE,EACrB,YAAqB,KAAK;;YAE1B,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC3D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC1C,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC;gBAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC;aACpD,CAAC,CAAC;YAEH,OAAO;gBACL,KAAK;gBACL,QAAQ;gBACR,IAAI;gBACJ,QAAQ;aACT,CAAC;QACJ,CAAC;KAAA;IAEY,mBAAmB,CAC9B,QAAuB,EACvB,OAAe,CAAC,EAChB,WAAmB,EAAE;;YAErB,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,QAAQ,CAAC,CAAC;QACpD,CAAC;KAAA;IAEY,eAAe,CAC1B,QAAuB,EACvB,OAAe,CAAC,EAChB,WAAmB,EAAE,EACrB,YAAqB,KAAK;;YAE1B,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7D,CAAC;KAAA;IAEY,SAAS,CAAC,KAAa;;YAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;KAAA;IAEY,MAAM,CACjB,KAAa;;YAEb,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;KAAA;IAEY,YAAY,CAAC,KAAa;;YACrC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3C,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,mCAAgB,CAAC,KAAK,CAAC,CAAC;YAC5C,OAAO,GAAG,CAAC;QACb,CAAC;KAAA;IAEY,gBAAgB,CAAC,KAAa,EAAE,OAAe;;YAC1D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAE3C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,KAAK,KAAK,oBAAY,CAAC,OAAO,EAAE;gBAClC,MAAM,IAAI,mDAAwB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;aAClD;YAED,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;KAAA;IAEK,KAAK;;YACT,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC;KAAA;IAED,IAAY,KAAK;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAxJD,sBAwJC"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,22 @@
1
- export { ConnectionOptions, RedisOptions, Job, Worker as RawWorker, WorkerOptions, Queue as RawQueue, QueueOptions, JobsOptions, } from "bullmq";
1
+ export { ConnectionOptions, RedisOptions, Job, Worker as RawWorker, WorkerOptions, Queue as RawQueue, QueueOptions, JobState, JobType, JobsOptions, } from "bullmq";
2
2
  export declare type JobData = unknown;
3
3
  export declare type JobReturnValue = unknown;
4
+ export declare enum JobStateEnum {
5
+ ACTIVE = "active",
6
+ DELAYED = "delayed",
7
+ WAITING = "waiting",
8
+ COMPLETED = "completed",
9
+ FAILED = "failed",
10
+ WAITING_CHILDREN = "waiting-children"
11
+ }
12
+ export declare enum JobTypeEnum {
13
+ ACTIVE = "active",
14
+ DELAYED = "delayed",
15
+ WAITING = "waiting",
16
+ COMPLETED = "completed",
17
+ FAILED = "failed",
18
+ WAITING_CHILDREN = "waiting-children",
19
+ PAUSED = "paused",
20
+ REPEAT = "repeat",
21
+ WAIT = "wait"
22
+ }
package/dist/types.js CHANGED
@@ -1,9 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RawQueue = exports.RawWorker = exports.Job = void 0;
3
+ exports.JobTypeEnum = exports.JobStateEnum = exports.RawQueue = exports.RawWorker = exports.Job = void 0;
4
4
  // decoupling from bullmq
5
5
  var bullmq_1 = require("bullmq");
6
6
  Object.defineProperty(exports, "Job", { enumerable: true, get: function () { return bullmq_1.Job; } });
7
7
  Object.defineProperty(exports, "RawWorker", { enumerable: true, get: function () { return bullmq_1.Worker; } });
8
8
  Object.defineProperty(exports, "RawQueue", { enumerable: true, get: function () { return bullmq_1.Queue; } });
9
+ var JobStateEnum;
10
+ (function (JobStateEnum) {
11
+ JobStateEnum["ACTIVE"] = "active";
12
+ JobStateEnum["DELAYED"] = "delayed";
13
+ JobStateEnum["WAITING"] = "waiting";
14
+ JobStateEnum["COMPLETED"] = "completed";
15
+ JobStateEnum["FAILED"] = "failed";
16
+ JobStateEnum["WAITING_CHILDREN"] = "waiting-children";
17
+ })(JobStateEnum = exports.JobStateEnum || (exports.JobStateEnum = {}));
18
+ var JobTypeEnum;
19
+ (function (JobTypeEnum) {
20
+ JobTypeEnum["ACTIVE"] = "active";
21
+ JobTypeEnum["DELAYED"] = "delayed";
22
+ JobTypeEnum["WAITING"] = "waiting";
23
+ JobTypeEnum["COMPLETED"] = "completed";
24
+ JobTypeEnum["FAILED"] = "failed";
25
+ JobTypeEnum["WAITING_CHILDREN"] = "waiting-children";
26
+ JobTypeEnum["PAUSED"] = "paused";
27
+ JobTypeEnum["REPEAT"] = "repeat";
28
+ JobTypeEnum["WAIT"] = "wait";
29
+ })(JobTypeEnum = exports.JobTypeEnum || (exports.JobTypeEnum = {}));
9
30
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AACzB,iCASgB;AANd,6FAAA,GAAG,OAAA;AACH,mGAAA,MAAM,OAAa;AAEnB,kGAAA,KAAK,OAAY"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AACzB,iCAWgB;AARd,6FAAA,GAAG,OAAA;AACH,mGAAA,MAAM,OAAa;AAEnB,kGAAA,KAAK,OAAY;AAWnB,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,iCAAiB,CAAA;IACjB,mCAAmB,CAAA;IACnB,mCAAmB,CAAA;IACnB,uCAAuB,CAAA;IACvB,iCAAiB,CAAA;IACjB,qDAAqC,CAAA;AACvC,CAAC,EAPW,YAAY,GAAZ,oBAAY,KAAZ,oBAAY,QAOvB;AAED,IAAY,WAUX;AAVD,WAAY,WAAW;IACrB,gCAAiB,CAAA;IACjB,kCAAmB,CAAA;IACnB,kCAAmB,CAAA;IACnB,sCAAuB,CAAA;IACvB,gCAAiB,CAAA;IACjB,oDAAqC,CAAA;IACrC,gCAAiB,CAAA;IACjB,gCAAiB,CAAA;IACjB,4BAAa,CAAA;AACf,CAAC,EAVW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAUtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alanszp/queue",
3
- "version": "9.2.4",
3
+ "version": "9.2.6",
4
4
  "description": "Workers and queues",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -26,11 +26,12 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@alanszp/audit": "^9.0.0",
29
+ "@alanszp/core": "^9.2.2",
29
30
  "@alanszp/logger": "^9.0.0",
30
31
  "@alanszp/shared-context": "^9.0.0",
31
32
  "bullmq": "^2.1.2",
32
33
  "ioredis": "^5.2.3",
33
34
  "lodash": "^4.17.21"
34
35
  },
35
- "gitHead": "0f35519e3073a3b4aa2b0060303eacf228d321ee"
36
+ "gitHead": "a5e4b5c25d8acdbfdf1cfa07791c620cc0d2fff5"
36
37
  }
@@ -0,0 +1,32 @@
1
+ import { BaseError, RenderableContext, RenderableError } from "@alanszp/errors";
2
+ import { JobState } from "bullmq";
3
+
4
+ export class JobCannotBePromotedError
5
+ extends BaseError
6
+ implements RenderableError
7
+ {
8
+ public jobId: string;
9
+
10
+ public currentJobState: JobState | "unknown";
11
+
12
+ constructor(jobId: string, currentJobState: JobState | "unknown") {
13
+ super("JobCannotBePromotedError");
14
+ this.jobId = jobId;
15
+ this.currentJobState = currentJobState;
16
+ }
17
+
18
+ code(): string {
19
+ return "job_cannot_be_promoted_error";
20
+ }
21
+
22
+ renderMessage(): string {
23
+ return "Job not found";
24
+ }
25
+
26
+ context(): RenderableContext {
27
+ return {
28
+ jobId: this.jobId,
29
+ currentJobState: this.currentJobState,
30
+ };
31
+ }
32
+ }
@@ -0,0 +1,24 @@
1
+ import { BaseError, RenderableContext, RenderableError } from "@alanszp/errors";
2
+
3
+ export class JobNotFoundError extends BaseError implements RenderableError {
4
+ public jobId: string;
5
+
6
+ constructor(jobId: string) {
7
+ super("JobNotFoundError");
8
+ this.jobId = jobId;
9
+ }
10
+
11
+ code(): string {
12
+ return "job_not_found_error";
13
+ }
14
+
15
+ renderMessage(): string {
16
+ return "Job not found";
17
+ }
18
+
19
+ context(): RenderableContext {
20
+ return {
21
+ jobId: this.jobId,
22
+ };
23
+ }
24
+ }
@@ -4,13 +4,13 @@ import { ConnectionManager } from "../connectionManager";
4
4
  import { JobData, QueueOptions } from "../types";
5
5
  import { SharedContext } from "@alanszp/shared-context";
6
6
 
7
- export function createQueue<JobType = JobData>(
7
+ export function createQueue<Data = JobData>(
8
8
  name: string,
9
9
  getContext: () => SharedContext,
10
10
  queueOptions?: QueueOptions
11
- ): Queue {
11
+ ): Queue<Data> {
12
12
  const connection = ConnectionManager.getInstance().getConnection();
13
- const queue = new Queue<JobType>(
13
+ const queue = new Queue<Data>(
14
14
  connection,
15
15
  name,
16
16
  ConnectionManager.getInstance().getServiceName(),
@@ -1,14 +1,27 @@
1
- import { merge } from "lodash";
1
+ import { capitalize, merge } from "lodash";
2
2
  import { Job, JobsOptions } from "bullmq";
3
+ import { ListResult } from "@alanszp/core";
3
4
  import { SharedContext } from "@alanszp/shared-context";
4
- import { ConnectionOptions, JobData, QueueOptions, RawQueue } from "../types";
5
+ import {
6
+ ConnectionOptions,
7
+ JobData,
8
+ JobReturnValue,
9
+ JobStateEnum,
10
+ JobTypeEnum,
11
+ QueueOptions,
12
+ RawQueue,
13
+ } from "../types";
14
+ import { JobNotFoundError } from "../errors/JobNotFoundError";
15
+ import { JobCannotBePromotedError } from "../errors/JobCannotBePromotedError";
16
+ import { ResultTypes } from "ioredis/built/utils/RedisCommander";
5
17
 
6
18
  const BULL_PREFIX = "b";
7
19
 
8
20
  const DEFAULT_COMPLETED_JOB_MAX_AGE_IN_SECONDS = 60 * 60 * 24 * 30;
9
21
  const DEFAULT_COMPLETED_JOB_MAX_COUNT = 500;
22
+ const DEFAULT_FAILED_JOB_MAX_COUNT = 1000;
10
23
 
11
- export class Queue<JobType = JobData> {
24
+ export class Queue<Data = JobData, ReturnValue = JobReturnValue> {
12
25
  private _queue: RawQueue;
13
26
 
14
27
  private name: string;
@@ -26,7 +39,7 @@ export class Queue<JobType = JobData> {
26
39
 
27
40
  this.getSharedContext = getSharedContext;
28
41
 
29
- this._queue = new RawQueue<JobType>(name, {
42
+ this._queue = new RawQueue<Data>(name, {
30
43
  ...merge(
31
44
  {
32
45
  defaultJobOptions: {
@@ -34,6 +47,9 @@ export class Queue<JobType = JobData> {
34
47
  age: DEFAULT_COMPLETED_JOB_MAX_AGE_IN_SECONDS,
35
48
  count: DEFAULT_COMPLETED_JOB_MAX_COUNT,
36
49
  },
50
+ removeOnFail: {
51
+ count: DEFAULT_FAILED_JOB_MAX_COUNT,
52
+ },
37
53
  attempts: 3,
38
54
  backoff: {
39
55
  type: "exponential",
@@ -52,34 +68,109 @@ export class Queue<JobType = JobData> {
52
68
  return this.name;
53
69
  }
54
70
 
55
- async publishJob(job: JobType, opts?: JobsOptions): Promise<Job<JobType>> {
71
+ async publishJob(
72
+ job: Data,
73
+ opts?: JobsOptions
74
+ ): Promise<Job<Data, ReturnValue>> {
56
75
  const context = this.getSharedContext();
57
76
  const lid = context.getLifecycleId();
58
77
  const lch = context.getLifecycleChain();
59
78
  return this.queue.add(this.name, { ...job, lid, lch }, opts);
60
79
  }
61
80
 
62
- async publishBulkJob(jobDatas: JobType[]): Promise<Job<JobType>[]> {
81
+ async publishBulkJob(jobDatas: Data[]): Promise<Job<Data, ReturnValue>[]> {
63
82
  const jobs = jobDatas.map((data) => ({ name: this.name, data }));
64
83
  return this.queue.addBulk(jobs);
65
84
  }
66
85
 
67
86
  async publishBulkJobWithOptions(
68
- jobDefinitions: { jobData: JobType; opts: JobsOptions }[]
69
- ): Promise<void> {
87
+ jobDefinitions: { jobData: Data; opts: JobsOptions }[]
88
+ ): Promise<Job<Data, ReturnValue>[]> {
70
89
  const jobs = jobDefinitions.map(({ jobData: data, opts }) => ({
71
90
  name: this.name,
72
91
  data,
73
92
  opts,
74
93
  }));
75
- await this.queue.addBulk(jobs);
94
+ return this.queue.addBulk(jobs);
95
+ }
96
+
97
+ private pageToStartEnd(pageNumber: number, pageSize: number) {
98
+ return {
99
+ start: (pageNumber - 1) * pageSize,
100
+ end: pageNumber * pageSize - 1,
101
+ };
102
+ }
103
+
104
+ public async getJobsAndCountByStatus(
105
+ statuses: JobTypeEnum[],
106
+ page: number = 1,
107
+ pageSize: number = 50,
108
+ ascending: boolean = false
109
+ ): Promise<ListResult<Job<Data, ReturnValue>>> {
110
+ const { start, end } = this.pageToStartEnd(page, pageSize);
111
+ const [total, elements] = await Promise.all([
112
+ this.queue.getJobCountByTypes(...statuses),
113
+ this.queue.getJobs(statuses, start, end, ascending),
114
+ ]);
115
+
116
+ return {
117
+ total,
118
+ elements,
119
+ page,
120
+ pageSize,
121
+ };
122
+ }
123
+
124
+ public async getJobCountByStatus(
125
+ statuses: JobTypeEnum[],
126
+ page: number = 1,
127
+ pageSize: number = 50
128
+ ): Promise<number> {
129
+ return this.queue.getJobCountByTypes(...statuses);
130
+ }
131
+
132
+ public async getJobsByStatus(
133
+ statuses: JobTypeEnum[],
134
+ page: number = 1,
135
+ pageSize: number = 50,
136
+ ascending: boolean = false
137
+ ): Promise<Job<Data, ReturnValue>[]> {
138
+ const { start, end } = this.pageToStartEnd(page, pageSize);
139
+ return this.queue.getJobs(statuses, start, end, ascending);
140
+ }
141
+
142
+ public async deleteJob(jobId: string) {
143
+ this.queue.remove(jobId);
144
+ }
145
+
146
+ public async getJob(
147
+ jobId: string
148
+ ): Promise<Job<Data, ReturnValue> | undefined> {
149
+ return this.queue.getJob(jobId);
150
+ }
151
+
152
+ public async getJobOrFail(jobId: string): Promise<Job<Data, ReturnValue>> {
153
+ const job = await this.queue.getJob(jobId);
154
+ if (!job) throw new JobNotFoundError(jobId);
155
+ return job;
156
+ }
157
+
158
+ public async changeDelayToJob(jobId: string, delayMs: number) {
159
+ const job = await this.getJobOrFail(jobId);
160
+
161
+ const state = await job.getState();
162
+ if (state !== JobStateEnum.DELAYED) {
163
+ throw new JobCannotBePromotedError(jobId, state);
164
+ }
165
+
166
+ job.changeDelay(delayMs);
76
167
  }
77
168
 
78
169
  async close(): Promise<void> {
79
170
  await this.queue.close();
80
171
  }
81
172
 
82
- private get queue(): RawQueue<JobType> {
173
+ private get queue(): RawQueue<Data, ReturnValue> {
83
174
  return this._queue;
84
175
  }
85
176
  }
package/src/types.ts CHANGED
@@ -7,9 +7,32 @@ export {
7
7
  WorkerOptions,
8
8
  Queue as RawQueue,
9
9
  QueueOptions,
10
+ JobState,
11
+ JobType,
10
12
  JobsOptions,
11
13
  } from "bullmq";
12
14
 
13
15
  export type JobData = unknown;
14
16
 
15
17
  export type JobReturnValue = unknown;
18
+
19
+ export enum JobStateEnum {
20
+ ACTIVE = "active",
21
+ DELAYED = "delayed",
22
+ WAITING = "waiting",
23
+ COMPLETED = "completed",
24
+ FAILED = "failed",
25
+ WAITING_CHILDREN = "waiting-children",
26
+ }
27
+
28
+ export enum JobTypeEnum {
29
+ ACTIVE = "active",
30
+ DELAYED = "delayed",
31
+ WAITING = "waiting",
32
+ COMPLETED = "completed",
33
+ FAILED = "failed",
34
+ WAITING_CHILDREN = "waiting-children",
35
+ PAUSED = "paused",
36
+ REPEAT = "repeat",
37
+ WAIT = "wait",
38
+ }