@alanszp/queue 9.2.4 → 9.3.0
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/dist/errors/JobCannotBePromotedError.d.ts +10 -0
- package/dist/errors/JobCannotBePromotedError.js +25 -0
- package/dist/errors/JobCannotBePromotedError.js.map +1 -0
- package/dist/errors/JobNotFoundError.d.ts +8 -0
- package/dist/errors/JobNotFoundError.js +23 -0
- package/dist/errors/JobNotFoundError.js.map +1 -0
- package/dist/jobsManagement/commands/asyncCreationCommands.d.ts +7 -0
- package/dist/jobsManagement/commands/asyncCreationCommands.js +45 -0
- package/dist/jobsManagement/commands/asyncCreationCommands.js.map +1 -0
- package/dist/jobsManagement/commands/getCommands.d.ts +8 -0
- package/dist/jobsManagement/commands/getCommands.js +47 -0
- package/dist/jobsManagement/commands/getCommands.js.map +1 -0
- package/dist/jobsManagement/commands/workerHealthCommand.d.ts +2 -0
- package/dist/jobsManagement/commands/workerHealthCommand.js +10 -0
- package/dist/jobsManagement/commands/workerHealthCommand.js.map +1 -0
- package/dist/jobsManagement/index.d.ts +6 -0
- package/dist/jobsManagement/index.js +19 -0
- package/dist/jobsManagement/index.js.map +1 -0
- package/dist/jobsManagement/inputs/CreateAsyncJobInput.d.ts +11 -0
- package/dist/jobsManagement/inputs/CreateAsyncJobInput.js +58 -0
- package/dist/jobsManagement/inputs/CreateAsyncJobInput.js.map +1 -0
- package/dist/jobsManagement/inputs/GetJobInput.d.ts +6 -0
- package/dist/jobsManagement/inputs/GetJobInput.js +44 -0
- package/dist/jobsManagement/inputs/GetJobInput.js.map +1 -0
- package/dist/jobsManagement/inputs/SearchJobsInput.d.ts +14 -0
- package/dist/jobsManagement/inputs/SearchJobsInput.js +61 -0
- package/dist/jobsManagement/inputs/SearchJobsInput.js.map +1 -0
- package/dist/queue/createQueue.d.ts +1 -1
- package/dist/queue/queue.d.ts +15 -6
- package/dist/queue/queue.js +67 -1
- package/dist/queue/queue.js.map +1 -1
- package/dist/reporter/totalCount/ITotalCountReporter.d.ts +5 -0
- package/dist/reporter/totalCount/ITotalCountReporter.js +3 -0
- package/dist/reporter/totalCount/ITotalCountReporter.js.map +1 -0
- package/dist/reporter/totalCount/JobTotalCountReporter.d.ts +12 -0
- package/dist/reporter/totalCount/JobTotalCountReporter.js +29 -0
- package/dist/reporter/totalCount/JobTotalCountReporter.js.map +1 -0
- package/dist/reporter/totalCount/MockTotalCountReporter.d.ts +8 -0
- package/dist/reporter/totalCount/MockTotalCountReporter.js +21 -0
- package/dist/reporter/totalCount/MockTotalCountReporter.js.map +1 -0
- package/dist/types.d.ts +20 -1
- package/dist/types.js +22 -1
- package/dist/types.js.map +1 -1
- package/dist/worker/workerRepository.d.ts +2 -2
- package/dist/worker/workerRepository.js +7 -2
- package/dist/worker/workerRepository.js.map +1 -1
- package/package.json +5 -2
- package/src/errors/JobCannotBePromotedError.ts +32 -0
- package/src/errors/JobNotFoundError.ts +24 -0
- package/src/jobsManagement/commands/asyncCreationCommands.ts +58 -0
- package/src/jobsManagement/commands/getCommands.ts +57 -0
- package/src/jobsManagement/commands/workerHealthCommand.ts +10 -0
- package/src/jobsManagement/index.ts +6 -0
- package/src/jobsManagement/inputs/CreateAsyncJobInput.ts +37 -0
- package/src/jobsManagement/inputs/GetJobInput.ts +17 -0
- package/src/jobsManagement/inputs/SearchJobsInput.ts +45 -0
- package/src/queue/createQueue.ts +3 -3
- package/src/queue/queue.ts +101 -10
- package/src/reporter/totalCount/ITotalCountReporter.ts +5 -0
- package/src/reporter/totalCount/JobTotalCountReporter.ts +37 -0
- package/src/reporter/totalCount/MockTotalCountReporter.ts +20 -0
- package/src/types.ts +23 -0
- package/src/worker/workerRepository.ts +13 -5
package/src/queue/queue.ts
CHANGED
|
@@ -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 {
|
|
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<
|
|
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<
|
|
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(
|
|
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:
|
|
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:
|
|
69
|
-
): Promise<
|
|
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
|
-
|
|
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<
|
|
173
|
+
private get queue(): RawQueue<Data, ReturnValue> {
|
|
83
174
|
return this._queue;
|
|
84
175
|
}
|
|
85
176
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Job } from "../../types";
|
|
2
|
+
import { ITotalCountReporter } from "./ITotalCountReporter";
|
|
3
|
+
|
|
4
|
+
export class JobTotalCountReporter<JobInstance extends Job>
|
|
5
|
+
implements ITotalCountReporter
|
|
6
|
+
{
|
|
7
|
+
private total = 1;
|
|
8
|
+
|
|
9
|
+
private current = 0;
|
|
10
|
+
|
|
11
|
+
private job: JobInstance;
|
|
12
|
+
|
|
13
|
+
constructor(job: JobInstance) {
|
|
14
|
+
this.job = job;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setTotal(total: number): void {
|
|
18
|
+
this.total = total;
|
|
19
|
+
this.reset();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
increment(n?: number): void {
|
|
23
|
+
this.current += n ?? 1;
|
|
24
|
+
this.report();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
reset(value?: number): void {
|
|
28
|
+
this.current = value ?? 0;
|
|
29
|
+
this.report();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
report() {
|
|
33
|
+
this.job
|
|
34
|
+
.updateProgress({ total: this.total, current: this.current })
|
|
35
|
+
.catch(() => {});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ITotalCountReporter } from "./ITotalCountReporter";
|
|
2
|
+
|
|
3
|
+
export class MockTotalCountReporter implements ITotalCountReporter {
|
|
4
|
+
private total = 1;
|
|
5
|
+
|
|
6
|
+
private progress = 0;
|
|
7
|
+
|
|
8
|
+
setTotal(total: number): void {
|
|
9
|
+
this.total = total;
|
|
10
|
+
this.reset();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
increment(n?: number): void {
|
|
14
|
+
this.progress += n ?? 1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
reset(value?: number): void {
|
|
18
|
+
this.progress = value ?? 0;
|
|
19
|
+
}
|
|
20
|
+
}
|
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
|
+
}
|
|
@@ -3,7 +3,7 @@ import { compact, isEmpty } from "lodash";
|
|
|
3
3
|
import { ConnectionManager } from "../connectionManager";
|
|
4
4
|
import { Worker, WorkerStatus } from "./worker";
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type WorkerStatusWithId = { status: WorkerStatus } & { id: string };
|
|
7
7
|
interface WorkerClass {
|
|
8
8
|
new (): Worker;
|
|
9
9
|
}
|
|
@@ -32,7 +32,10 @@ export class WorkerRepository {
|
|
|
32
32
|
return this._instance;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
public registerWorker(
|
|
35
|
+
public registerWorker(
|
|
36
|
+
queueName: string,
|
|
37
|
+
workerClass: WorkerClass
|
|
38
|
+
): WorkerRepository {
|
|
36
39
|
Object.assign(this.workers, { [queueName]: workerClass });
|
|
37
40
|
return this;
|
|
38
41
|
}
|
|
@@ -51,14 +54,19 @@ export class WorkerRepository {
|
|
|
51
54
|
this._activeWorkers.push(worker);
|
|
52
55
|
return worker;
|
|
53
56
|
}
|
|
54
|
-
this.getLogger().warn("worker_repository.invalid_queue_name", {
|
|
57
|
+
this.getLogger().warn("worker_repository.invalid_queue_name", {
|
|
58
|
+
queueName,
|
|
59
|
+
});
|
|
55
60
|
return null;
|
|
56
61
|
})
|
|
57
62
|
);
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
getWorkerStatuses():
|
|
61
|
-
return this.activeWorkers.map((worker) => ({
|
|
65
|
+
getWorkerStatuses(): WorkerStatusWithId[] {
|
|
66
|
+
return this.activeWorkers.map((worker) => ({
|
|
67
|
+
id: worker.id,
|
|
68
|
+
status: worker.status,
|
|
69
|
+
}));
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
public getCloseConnections(): Promise<void>[] {
|