vona-module-a-queue 5.0.9 → 5.0.10
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/.metadata/index.d.ts +70 -0
- package/dist/.metadata/index.js +32 -0
- package/dist/.metadata/this.d.ts +2 -0
- package/dist/.metadata/this.js +2 -0
- package/dist/bean/startup.loadQueueWorkers.d.ts +5 -0
- package/dist/bean/startup.loadQueueWorkers.js +20 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/config.js +9 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/lib/beanQueueBase.d.ts +7 -0
- package/dist/lib/beanQueueBase.js +12 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +2 -0
- package/dist/lib/queue.d.ts +2 -0
- package/dist/lib/queue.js +4 -0
- package/dist/monkey.d.ts +6 -0
- package/dist/monkey.js +12 -0
- package/dist/service/queue.d.ts +25 -0
- package/dist/service/queue.js +250 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/queue.d.ts +71 -0
- package/dist/types/queue.js +1 -0
- package/package.json +7 -3
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { BeanScopeUtil, TypeModuleConfig } from 'vona';
|
|
2
|
+
/** startup: begin */
|
|
3
|
+
import type { IDecoratorStartupOptions } from 'vona-module-a-startup';
|
|
4
|
+
import type { config } from '../config/config.ts';
|
|
5
|
+
/** service: end */
|
|
6
|
+
/** service: begin */
|
|
7
|
+
import type { ServiceQueue } from '../service/queue.ts';
|
|
8
|
+
/** service: end */
|
|
9
|
+
/** service: begin */
|
|
10
|
+
/** monkey: end */
|
|
11
|
+
/** scope: begin */
|
|
12
|
+
import { BeanScopeBase } from 'vona';
|
|
13
|
+
import 'vona';
|
|
14
|
+
import 'vona';
|
|
15
|
+
import 'vona';
|
|
16
|
+
export * from '../bean/startup.loadQueueWorkers.ts';
|
|
17
|
+
declare module 'vona-module-a-startup' {
|
|
18
|
+
interface IStartupRecord {
|
|
19
|
+
'a-queue:loadQueueWorkers': IDecoratorStartupOptions;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
declare module 'vona-module-a-queue' {
|
|
23
|
+
interface StartupLoadQueueWorkers {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** service: end */
|
|
27
|
+
/** config: begin */
|
|
28
|
+
export * from '../config/config.ts';
|
|
29
|
+
declare module 'vona-module-a-web' {
|
|
30
|
+
interface IServiceRecord {
|
|
31
|
+
'a-queue:queue': never;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
declare module 'vona-module-a-queue' {
|
|
35
|
+
interface ServiceQueue {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export interface IModuleService {
|
|
39
|
+
queue: ServiceQueue;
|
|
40
|
+
}
|
|
41
|
+
declare module 'vona' {
|
|
42
|
+
interface IBeanRecordGeneral {
|
|
43
|
+
'a-queue.service.queue': ServiceQueue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** config: end */
|
|
47
|
+
/** monkey: begin */
|
|
48
|
+
export * from '../monkey.ts';
|
|
49
|
+
/** startup: end */
|
|
50
|
+
/** service: begin */
|
|
51
|
+
export * from '../service/queue.ts';
|
|
52
|
+
export declare class ScopeModuleAQueue extends BeanScopeBase {
|
|
53
|
+
}
|
|
54
|
+
export interface ScopeModuleAQueue {
|
|
55
|
+
util: BeanScopeUtil;
|
|
56
|
+
config: TypeModuleConfig<typeof config>;
|
|
57
|
+
service: IModuleService;
|
|
58
|
+
}
|
|
59
|
+
declare module 'vona' {
|
|
60
|
+
interface IBeanScopeRecord {
|
|
61
|
+
'a-queue': ScopeModuleAQueue;
|
|
62
|
+
}
|
|
63
|
+
interface IBeanScopeContainer {
|
|
64
|
+
queue: ScopeModuleAQueue;
|
|
65
|
+
}
|
|
66
|
+
interface IBeanScopeConfig {
|
|
67
|
+
'a-queue': ReturnType<typeof config>;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** scope: end */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/** service: end */
|
|
8
|
+
/** service: begin */
|
|
9
|
+
/** monkey: end */
|
|
10
|
+
/** scope: begin */
|
|
11
|
+
import { BeanScopeBase } from 'vona';
|
|
12
|
+
import { Scope } from 'vona-module-a-bean';
|
|
13
|
+
import 'vona';
|
|
14
|
+
import 'vona';
|
|
15
|
+
import 'vona';
|
|
16
|
+
export * from "../bean/startup.loadQueueWorkers.js";
|
|
17
|
+
/** service: end */
|
|
18
|
+
/** config: begin */
|
|
19
|
+
export * from "../config/config.js";
|
|
20
|
+
/** config: end */
|
|
21
|
+
/** monkey: begin */
|
|
22
|
+
export * from "../monkey.js";
|
|
23
|
+
/** startup: end */
|
|
24
|
+
/** service: begin */
|
|
25
|
+
export * from "../service/queue.js";
|
|
26
|
+
let ScopeModuleAQueue = class ScopeModuleAQueue extends BeanScopeBase {
|
|
27
|
+
};
|
|
28
|
+
ScopeModuleAQueue = __decorate([
|
|
29
|
+
Scope()
|
|
30
|
+
], ScopeModuleAQueue);
|
|
31
|
+
export { ScopeModuleAQueue };
|
|
32
|
+
/** scope: end */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BeanBase } from 'vona';
|
|
8
|
+
import { Startup } from 'vona-module-a-startup';
|
|
9
|
+
let StartupLoadQueueWorkers = class StartupLoadQueueWorkers extends BeanBase {
|
|
10
|
+
async execute() {
|
|
11
|
+
// load queue workers
|
|
12
|
+
if (!this.app.meta.isTest) {
|
|
13
|
+
this.scope.service.queue.loadQueueWorkers(this.ctx.instanceName);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
StartupLoadQueueWorkers = __decorate([
|
|
18
|
+
Startup({ instance: true, after: true })
|
|
19
|
+
], StartupLoadQueueWorkers);
|
|
20
|
+
export { StartupLoadQueueWorkers };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IQueuePushOptions } from '../types/queue.ts';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
export declare class BeanQueueBase<DATA = unknown, RESULT = unknown> extends BeanBase {
|
|
4
|
+
pushAsync(data: DATA, options?: IQueuePushOptions): Promise<RESULT>;
|
|
5
|
+
push(data: DATA, options?: IQueuePushOptions): void;
|
|
6
|
+
getQueue(instanceName?: string): import("bullmq").Queue<any, any, string, any, any, string>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BeanBase } from 'vona';
|
|
2
|
+
export class BeanQueueBase extends BeanBase {
|
|
3
|
+
async pushAsync(data, options) {
|
|
4
|
+
return await this.$scope.queue.service.queue.pushAsync(this.$scope.queue.service.queue.prepareJobInfo(this.$onionName, data, options));
|
|
5
|
+
}
|
|
6
|
+
push(data, options) {
|
|
7
|
+
return this.$scope.queue.service.queue.push(this.$scope.queue.service.queue.prepareJobInfo(this.$onionName, data, options));
|
|
8
|
+
}
|
|
9
|
+
getQueue(instanceName) {
|
|
10
|
+
return this.$scope.queue.service.queue.getQueue(this.$onionName, instanceName);
|
|
11
|
+
}
|
|
12
|
+
}
|
package/dist/monkey.d.ts
ADDED
package/dist/monkey.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BeanSimple } from 'vona';
|
|
2
|
+
import { __ThisModule__ } from "./.metadata/this.js";
|
|
3
|
+
export class Monkey extends BeanSimple {
|
|
4
|
+
async appClose() {
|
|
5
|
+
const scopeSelf = this.bean.scope(__ThisModule__);
|
|
6
|
+
await scopeSelf.service.queue.clearWorkers();
|
|
7
|
+
}
|
|
8
|
+
async appClosed() {
|
|
9
|
+
const scopeSelf = this.bean.scope(__ThisModule__);
|
|
10
|
+
await scopeSelf.service.queue.clearQueues();
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IQueueCallbacks, IQueueJobContext, IQueuePushOptions, IQueueQueue, IQueueQueues, IQueueRecord, IQueueWork, IQueueWorks, TypeQueueJob } from '../types/queue.ts';
|
|
2
|
+
import * as Bull from 'bullmq';
|
|
3
|
+
import { BeanBase } from 'vona';
|
|
4
|
+
export declare class ServiceQueue extends BeanBase {
|
|
5
|
+
_workers: IQueueWorks;
|
|
6
|
+
_queues: IQueueQueues;
|
|
7
|
+
_queueCallbacks: IQueueCallbacks;
|
|
8
|
+
push<DATA>(info: IQueueJobContext<DATA>): void;
|
|
9
|
+
pushAsync<DATA, RESULT>(info: IQueueJobContext<DATA>): Promise<RESULT>;
|
|
10
|
+
loadQueueWorkers(instanceName?: string | undefined | null): void;
|
|
11
|
+
clearWorkers(): Promise<void>;
|
|
12
|
+
clearQueues(): Promise<void>;
|
|
13
|
+
_createWorker<DATA>(info: IQueueJobContext<DATA>, queueKey: string): IQueueWork;
|
|
14
|
+
_createQueue<DATA>(info: IQueueJobContext<DATA>, queueKey: string): IQueueQueue;
|
|
15
|
+
_ensureWorker<DATA>(info: IQueueJobContext<DATA>): void;
|
|
16
|
+
_ensureQueue<DATA>(info: IQueueJobContext<DATA>): IQueueQueue;
|
|
17
|
+
getQueue(queueName: keyof IQueueRecord, instanceName?: string | undefined | null): Bull.Queue<any, any, string, any, any, string>;
|
|
18
|
+
_getQueue<DATA>(info: IQueueJobContext<DATA>): Bull.Queue<any, any, string, any, any, string>;
|
|
19
|
+
_callCallback<DATA>(jobId: string | number, failedReason: string | undefined, data: DATA | undefined): void;
|
|
20
|
+
_queuePush<DATA, RESULT>(info: IQueueJobContext<DATA>, isAsync: boolean): Promise<RESULT>;
|
|
21
|
+
_combineQueueKey<DATA>(info: IQueueJobContext<DATA>): string;
|
|
22
|
+
_performTask<DATA, RESULT>(job: TypeQueueJob<DATA, RESULT>): Promise<unknown>;
|
|
23
|
+
getRepeatKey(jobName: string, repeat: Bull.RepeatOptions): string;
|
|
24
|
+
prepareJobInfo<DATA>(queueName: keyof IQueueRecord, data: DATA, options?: IQueuePushOptions): IQueueJobContext<DATA>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import * as Bull from 'bullmq';
|
|
8
|
+
import { BeanBase, beanFullNameFromOnionName, deepExtend, instanceDesp, uuidv4 } from 'vona';
|
|
9
|
+
import { Service } from 'vona-module-a-web';
|
|
10
|
+
let ServiceQueue = class ServiceQueue extends BeanBase {
|
|
11
|
+
_workers = {};
|
|
12
|
+
_queues = {};
|
|
13
|
+
_queueCallbacks = {};
|
|
14
|
+
push(info) {
|
|
15
|
+
if (!info.options?.dbInfo)
|
|
16
|
+
throw new Error('should specify the options.dbInfo');
|
|
17
|
+
this._queuePush(info, false);
|
|
18
|
+
}
|
|
19
|
+
// { locale, instanceName, module, queueName,queueNameSub,data }
|
|
20
|
+
pushAsync(info) {
|
|
21
|
+
if (!info.options?.dbInfo)
|
|
22
|
+
throw new Error('should specify the options.dbInfo');
|
|
23
|
+
return this._queuePush(info, true);
|
|
24
|
+
}
|
|
25
|
+
loadQueueWorkers(instanceName) {
|
|
26
|
+
for (const queueItem of this.bean.onion.queue.getOnionsEnabled()) {
|
|
27
|
+
const info = {
|
|
28
|
+
queueName: queueItem.name,
|
|
29
|
+
data: undefined,
|
|
30
|
+
options: {
|
|
31
|
+
instanceName,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
this._ensureWorker(info);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async clearWorkers() {
|
|
38
|
+
for (const queueKey in this._workers) {
|
|
39
|
+
const _worker = this._workers[queueKey];
|
|
40
|
+
await _worker.worker.close();
|
|
41
|
+
}
|
|
42
|
+
this._workers = {};
|
|
43
|
+
}
|
|
44
|
+
async clearQueues() {
|
|
45
|
+
for (const queueKey in this._queues) {
|
|
46
|
+
const _queue = this._queues[queueKey];
|
|
47
|
+
await _queue.queue.close();
|
|
48
|
+
await _queue.queueEvents.close();
|
|
49
|
+
}
|
|
50
|
+
this._queues = {};
|
|
51
|
+
}
|
|
52
|
+
_createWorker(info, queueKey) {
|
|
53
|
+
const app = this.app;
|
|
54
|
+
// worker
|
|
55
|
+
const _worker = {};
|
|
56
|
+
// prefix
|
|
57
|
+
const prefix = `bull_${app.name}:queue`;
|
|
58
|
+
// queue config
|
|
59
|
+
const queueConfig = app.bean.onion.queue.getOnionOptions(info.queueName);
|
|
60
|
+
// queueConfig.options: queue/worker/job/redlock
|
|
61
|
+
const workerOptions = queueConfig?.options?.worker;
|
|
62
|
+
const redlockOptions = queueConfig?.options?.redlock;
|
|
63
|
+
const _redlockOptions = Object.assign({}, this.$scope.redlock.config.redlock.options, redlockOptions);
|
|
64
|
+
const _lockTTL = redlockOptions?.lockTTL ?? this.$scope.redlock.config.redlock.lockTTL;
|
|
65
|
+
// redlock
|
|
66
|
+
if (!queueConfig?.concurrency) {
|
|
67
|
+
_worker.redlock = this.$scope.redlock.service.redlock.create(_redlockOptions);
|
|
68
|
+
}
|
|
69
|
+
// create work
|
|
70
|
+
const connectionWorker = app.bean.redis.get('queue');
|
|
71
|
+
const _workerOptions = Object.assign({}, this.scope.config.worker, workerOptions, {
|
|
72
|
+
prefix,
|
|
73
|
+
connection: connectionWorker,
|
|
74
|
+
});
|
|
75
|
+
_worker.workerOptions = _workerOptions;
|
|
76
|
+
_worker.worker = new Bull.Worker(queueKey, async (job) => {
|
|
77
|
+
// concurrency
|
|
78
|
+
if (queueConfig?.concurrency) {
|
|
79
|
+
return await this._performTask(job);
|
|
80
|
+
}
|
|
81
|
+
// redlock
|
|
82
|
+
const info = job.data;
|
|
83
|
+
const queueNameSub = info.options?.queueNameSub;
|
|
84
|
+
const _lockResource = `queue:${queueKey}${queueNameSub ? `#${queueNameSub}` : ''}`;
|
|
85
|
+
return await this.$scope.redlock.service.redlock.lock(_lockResource, async () => {
|
|
86
|
+
return await this._performTask(job);
|
|
87
|
+
}, {
|
|
88
|
+
// instanceName: job.data.instanceName, // need not
|
|
89
|
+
redlock: _worker.redlock,
|
|
90
|
+
lockTTL: _lockTTL,
|
|
91
|
+
});
|
|
92
|
+
}, _workerOptions);
|
|
93
|
+
_worker.worker.on('failed', (_job, err) => {
|
|
94
|
+
this.$logger.error(err);
|
|
95
|
+
});
|
|
96
|
+
_worker.worker.on('error', err => {
|
|
97
|
+
if (err.message && err.message.includes('Missing lock for job')) {
|
|
98
|
+
const workerInner = _worker.worker;
|
|
99
|
+
if (!workerInner.running) {
|
|
100
|
+
_worker.worker.run().catch(err => {
|
|
101
|
+
this.$logger.error(err);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
// ok
|
|
107
|
+
return _worker;
|
|
108
|
+
}
|
|
109
|
+
_createQueue(info, queueKey) {
|
|
110
|
+
const app = this.app;
|
|
111
|
+
// queue
|
|
112
|
+
const _queue = {};
|
|
113
|
+
// prefix
|
|
114
|
+
const prefix = `bull_${app.name}:queue`;
|
|
115
|
+
// queue config
|
|
116
|
+
const queueConfig = app.bean.onion.queue.getOnionOptions(info.queueName);
|
|
117
|
+
// queueConfig.options: queue/worker/job/limiter
|
|
118
|
+
const queueOptions = queueConfig?.options?.queue;
|
|
119
|
+
// create queue
|
|
120
|
+
const connectionQueue = app.bean.redis.get('queue');
|
|
121
|
+
const _queueOptions = Object.assign({}, queueOptions, { prefix, connection: connectionQueue });
|
|
122
|
+
_queue.config = queueConfig;
|
|
123
|
+
_queue.options = _queueOptions;
|
|
124
|
+
_queue.queue = new Bull.Queue(queueKey, _queueOptions);
|
|
125
|
+
// create events
|
|
126
|
+
const connectionEvents = app.bean.redis.get('queue');
|
|
127
|
+
const _queueEventsOptions = { prefix, connection: connectionEvents };
|
|
128
|
+
_queue.queueEventsOptions = _queueEventsOptions;
|
|
129
|
+
_queue.queueEvents = new Bull.QueueEvents(queueKey, _queueEventsOptions);
|
|
130
|
+
_queue.queueEvents.on('completed', ({ jobId, returnvalue }) => {
|
|
131
|
+
this._callCallback(jobId, undefined, returnvalue);
|
|
132
|
+
});
|
|
133
|
+
_queue.queueEvents.on('failed', ({ jobId, failedReason }) => {
|
|
134
|
+
this._callCallback(jobId, failedReason, undefined);
|
|
135
|
+
});
|
|
136
|
+
// ok
|
|
137
|
+
return _queue;
|
|
138
|
+
}
|
|
139
|
+
_ensureWorker(info) {
|
|
140
|
+
// queueKey
|
|
141
|
+
const queueKey = this._combineQueueKey(info);
|
|
142
|
+
// worker
|
|
143
|
+
if (!this._workers[queueKey]) {
|
|
144
|
+
this._workers[queueKey] = this._createWorker(info, queueKey);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
_ensureQueue(info) {
|
|
148
|
+
// worker
|
|
149
|
+
this._ensureWorker(info);
|
|
150
|
+
// queueKey
|
|
151
|
+
const queueKey = this._combineQueueKey(info);
|
|
152
|
+
// queue
|
|
153
|
+
if (!this._queues[queueKey]) {
|
|
154
|
+
this._queues[queueKey] = this._createQueue(info, queueKey);
|
|
155
|
+
}
|
|
156
|
+
// ok
|
|
157
|
+
return this._queues[queueKey];
|
|
158
|
+
}
|
|
159
|
+
getQueue(queueName, instanceName) {
|
|
160
|
+
return this._getQueue({
|
|
161
|
+
queueName,
|
|
162
|
+
data: undefined,
|
|
163
|
+
options: {
|
|
164
|
+
instanceName: instanceName ?? this.ctx.instanceName,
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
_getQueue(info) {
|
|
169
|
+
return this._ensureQueue(info).queue;
|
|
170
|
+
}
|
|
171
|
+
_callCallback(jobId, failedReason, data) {
|
|
172
|
+
const _callback = this._queueCallbacks[jobId];
|
|
173
|
+
if (_callback) {
|
|
174
|
+
delete this._queueCallbacks[jobId];
|
|
175
|
+
_callback.callback(failedReason ? new Error(failedReason) : undefined, data);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async _queuePush(info, isAsync) {
|
|
179
|
+
// queue config
|
|
180
|
+
const queueConfig = this.bean.onion.queue.getOnionOptions(info.queueName);
|
|
181
|
+
// queueConfig.options: queue/worker/job/limiter
|
|
182
|
+
const jobOptionsBase = queueConfig?.options?.job;
|
|
183
|
+
// queue
|
|
184
|
+
const queue = this._getQueue(info);
|
|
185
|
+
// job
|
|
186
|
+
const jobId = info.options?.jobOptions?.jobId || uuidv4();
|
|
187
|
+
const jobName = info.options?.jobName || jobId;
|
|
188
|
+
const jobOptions = deepExtend({ jobId }, jobOptionsBase, info.options?.jobOptions);
|
|
189
|
+
// should not change info, hold original info.options?.jobName, info.options?.jobOptions
|
|
190
|
+
// info = deepExtend({}, info, { options: { jobName, jobOptions } });
|
|
191
|
+
// not async
|
|
192
|
+
if (!isAsync) {
|
|
193
|
+
// add job
|
|
194
|
+
queue.add(jobName, info, jobOptions);
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
// async
|
|
198
|
+
return new Promise((resolve, reject) => {
|
|
199
|
+
// callback
|
|
200
|
+
this._queueCallbacks[jobId] = {
|
|
201
|
+
info,
|
|
202
|
+
callback: (err, data) => {
|
|
203
|
+
if (err)
|
|
204
|
+
return reject(err);
|
|
205
|
+
resolve(data);
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
// add job
|
|
209
|
+
return queue.add(jobName, info, jobOptions);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
_combineQueueKey(info) {
|
|
213
|
+
const instanceName = instanceDesp(info.options?.instanceName);
|
|
214
|
+
return `${instanceName}||${beanFullNameFromOnionName(info.queueName, 'queue')}`;
|
|
215
|
+
}
|
|
216
|
+
async _performTask(job) {
|
|
217
|
+
const info = job.data;
|
|
218
|
+
// queue config
|
|
219
|
+
const queueItem = this.bean.onion.queue.getOnionSlice(info.queueName);
|
|
220
|
+
const queueConfig = this.bean.onion.queue.getOnionOptions(info.queueName);
|
|
221
|
+
// execute
|
|
222
|
+
return await this.bean.executor.newCtx(async () => {
|
|
223
|
+
const beanFullName = queueItem.beanOptions.beanFullName;
|
|
224
|
+
const beanInstance = this.app.bean._getBean(beanFullName);
|
|
225
|
+
return await beanInstance.execute(info.data, info.options, job);
|
|
226
|
+
}, {
|
|
227
|
+
dbInfo: info.options?.dbInfo,
|
|
228
|
+
locale: info.options?.locale,
|
|
229
|
+
instanceName: info.options?.instanceName,
|
|
230
|
+
extraData: info.options?.extraData,
|
|
231
|
+
transaction: queueConfig?.transaction,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
getRepeatKey(jobName, repeat) {
|
|
235
|
+
const endDate = repeat.endDate ? new Date(repeat.endDate).getTime() : '';
|
|
236
|
+
const tz = repeat.tz || '';
|
|
237
|
+
const pattern = repeat.pattern;
|
|
238
|
+
const suffix = (pattern || String(repeat.every)) || '';
|
|
239
|
+
return `${jobName}:${endDate}:${tz}:${suffix}`;
|
|
240
|
+
}
|
|
241
|
+
prepareJobInfo(queueName, data, options) {
|
|
242
|
+
options = this.$scope.executor.service.executor.prepareGeneralInfo(options);
|
|
243
|
+
// info
|
|
244
|
+
return { queueName, data, options };
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
ServiceQueue = __decorate([
|
|
248
|
+
Service()
|
|
249
|
+
], ServiceQueue);
|
|
250
|
+
export { ServiceQueue };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './queue.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./queue.js";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type Redlock from '@sesamecare-oss/redlock';
|
|
2
|
+
import type * as Bull from 'bullmq';
|
|
3
|
+
import type { OmitNever } from 'vona';
|
|
4
|
+
import type { IGeneralInfoOptions } from 'vona-module-a-executor';
|
|
5
|
+
import type { IOnionOptionsEnable, ServiceOnion } from 'vona-module-a-onion';
|
|
6
|
+
export interface IQueuePushOptions extends IGeneralInfoOptions {
|
|
7
|
+
queueNameSub?: string;
|
|
8
|
+
jobName?: string;
|
|
9
|
+
jobOptions?: Bull.JobsOptions;
|
|
10
|
+
}
|
|
11
|
+
export type TypeQueueJob<DATA = unknown, RESULT = unknown> = Bull.Job<IQueueJobContext<DATA>, RESULT>;
|
|
12
|
+
export interface IQueueExecute<DATA = unknown, RESULT = unknown> {
|
|
13
|
+
execute: (data: DATA, options?: IQueuePushOptions, job?: TypeQueueJob<DATA, RESULT>) => Promise<RESULT>;
|
|
14
|
+
}
|
|
15
|
+
export interface IQueueJobContext<DATA> {
|
|
16
|
+
queueName: keyof IQueueRecord;
|
|
17
|
+
data: DATA;
|
|
18
|
+
options?: IQueuePushOptions;
|
|
19
|
+
}
|
|
20
|
+
export interface IQueueWork {
|
|
21
|
+
redlock: Redlock.Redlock;
|
|
22
|
+
worker: Bull.Worker;
|
|
23
|
+
workerOptions: Bull.WorkerOptions;
|
|
24
|
+
}
|
|
25
|
+
export interface IQueueWorks {
|
|
26
|
+
[queueKey: string]: IQueueWork;
|
|
27
|
+
}
|
|
28
|
+
export interface IQueueQueue {
|
|
29
|
+
config?: IDecoratorQueueOptions;
|
|
30
|
+
options: Bull.QueueOptions;
|
|
31
|
+
queue: Bull.Queue;
|
|
32
|
+
queueEvents: Bull.QueueEvents;
|
|
33
|
+
queueEventsOptions: Bull.QueueEventsOptions;
|
|
34
|
+
}
|
|
35
|
+
export interface IQueueQueues {
|
|
36
|
+
[queueKey: string]: IQueueQueue;
|
|
37
|
+
}
|
|
38
|
+
export interface IQueueCallback<DATA, RESULT> {
|
|
39
|
+
info: IQueueJobContext<DATA>;
|
|
40
|
+
callback: (err: Error | undefined, data: RESULT | undefined) => void;
|
|
41
|
+
}
|
|
42
|
+
export interface IQueueCallbacks {
|
|
43
|
+
[jobId: string | number]: IQueueCallback<unknown, unknown>;
|
|
44
|
+
}
|
|
45
|
+
export interface IQueueRecord {
|
|
46
|
+
}
|
|
47
|
+
export interface IDecoratorQueueOptions extends IOnionOptionsEnable {
|
|
48
|
+
concurrency?: boolean;
|
|
49
|
+
transaction?: boolean;
|
|
50
|
+
options?: {
|
|
51
|
+
queue?: Bull.QueueOptions;
|
|
52
|
+
worker?: Partial<Bull.WorkerOptions>;
|
|
53
|
+
redlock?: Redlock.Redlock & {
|
|
54
|
+
lockTTL?: number;
|
|
55
|
+
};
|
|
56
|
+
job?: Bull.JobsOptions;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
declare module 'vona-module-a-onion' {
|
|
60
|
+
interface BeanOnion {
|
|
61
|
+
queue: ServiceOnion<IDecoratorQueueOptions, keyof IQueueRecord>;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
declare module 'vona' {
|
|
65
|
+
interface ConfigOnions {
|
|
66
|
+
queue: OmitNever<IQueueRecord>;
|
|
67
|
+
}
|
|
68
|
+
interface IBeanSceneRecord {
|
|
69
|
+
queue: never;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona-module-a-queue",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.0.
|
|
4
|
+
"version": "5.0.10",
|
|
5
5
|
"title": "a-queue",
|
|
6
6
|
"vonaModule": {
|
|
7
7
|
"dependencies": {},
|
|
@@ -43,8 +43,12 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"bullmq": "^5.49.1"
|
|
45
45
|
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"clean-package": "^2.2.0",
|
|
48
|
+
"rimraf": "^6.0.1"
|
|
49
|
+
},
|
|
46
50
|
"scripts": {
|
|
47
|
-
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
48
|
-
"tsc:publish": "npm run clean && tsc"
|
|
51
|
+
"clean": "rimraf dist tsconfig.build.tsbuildinfo",
|
|
52
|
+
"tsc:publish": "npm run clean && tsc -p tsconfig.build.json"
|
|
49
53
|
}
|
|
50
54
|
}
|