@m16khb/nestjs-sidequest 0.1.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/index.cjs ADDED
@@ -0,0 +1,1037 @@
1
+ 'use strict';
2
+
3
+ var common = require('@nestjs/common');
4
+ var core = require('@nestjs/core');
5
+ var sidequest = require('sidequest');
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+
10
+ // src/constants.ts
11
+ var SIDEQUEST_MODULE_OPTIONS = Symbol("SIDEQUEST_MODULE_OPTIONS");
12
+ var SIDEQUEST_ENGINE = Symbol("SIDEQUEST_ENGINE");
13
+ var PROCESSOR_METADATA_KEY = Symbol("sidequest:processor");
14
+ var ON_JOB_METADATA_KEY = Symbol("sidequest:on-job");
15
+ var RETRY_OPTIONS_METADATA_KEY = Symbol("sidequest:retry");
16
+ var ON_JOB_COMPLETE_METADATA_KEY = Symbol("sidequest:on-job-complete");
17
+ var ON_JOB_FAILED_METADATA_KEY = Symbol("sidequest:on-job-failed");
18
+ var QUEUE_TOKEN_PREFIX = "SIDEQUEST_QUEUE_";
19
+ function getQueueToken(queueName) {
20
+ return `${QUEUE_TOKEN_PREFIX}${queueName}`;
21
+ }
22
+ __name(getQueueToken, "getQueueToken");
23
+ var DEFAULT_QUEUE_NAME = "default";
24
+ var DEFAULT_MAX_ATTEMPTS = 3;
25
+ var DEFAULT_TIMEOUT = 3e4;
26
+ var DEFAULT_CONCURRENCY = 10;
27
+ function _ts_decorate(decorators, target, key, desc) {
28
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30
+ 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;
31
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
32
+ }
33
+ __name(_ts_decorate, "_ts_decorate");
34
+ exports.SidequestAdapter = class _SidequestAdapter {
35
+ static {
36
+ __name(this, "SidequestAdapter");
37
+ }
38
+ logger = new common.Logger(_SidequestAdapter.name);
39
+ isStarted = false;
40
+ registeredJobs = /* @__PURE__ */ new Map();
41
+ /**
42
+ * Sidequest 엔진 시작
43
+ */
44
+ async start(options) {
45
+ if (this.isStarted) {
46
+ this.logger.warn("Sidequest engine is already started");
47
+ return;
48
+ }
49
+ this.logger.log("Starting Sidequest engine...");
50
+ try {
51
+ const config = {
52
+ backend: {
53
+ driver: options.backend.driver,
54
+ config: options.backend.config
55
+ }
56
+ };
57
+ if (options.queues) {
58
+ config.queues = options.queues.map((q) => ({
59
+ name: q.name,
60
+ concurrency: q.concurrency,
61
+ priority: q.priority,
62
+ state: q.state
63
+ }));
64
+ }
65
+ if (options.maxConcurrentJobs !== void 0) {
66
+ config.maxConcurrentJobs = options.maxConcurrentJobs;
67
+ }
68
+ if (options.minThreads !== void 0) {
69
+ config.minThreads = options.minThreads;
70
+ }
71
+ if (options.maxThreads !== void 0) {
72
+ config.maxThreads = options.maxThreads;
73
+ }
74
+ if (options.jobPollingInterval !== void 0) {
75
+ config.jobPollingInterval = options.jobPollingInterval;
76
+ }
77
+ if (options.releaseStaleJobsIntervalMin !== void 0) {
78
+ config.releaseStaleJobsIntervalMin = options.releaseStaleJobsIntervalMin;
79
+ }
80
+ if (options.cleanupFinishedJobsIntervalMin !== void 0) {
81
+ config.cleanupFinishedJobsIntervalMin = options.cleanupFinishedJobsIntervalMin;
82
+ }
83
+ if (options.logger) {
84
+ config.logger = {
85
+ level: options.logger.level ?? "info",
86
+ json: options.logger.json ?? false
87
+ };
88
+ }
89
+ if (options.dashboard) {
90
+ config.dashboard = options.dashboard;
91
+ }
92
+ await sidequest.Sidequest.start(config);
93
+ this.isStarted = true;
94
+ this.logger.log("Sidequest engine started");
95
+ } catch (error) {
96
+ this.logger.error("Failed to start Sidequest engine", error);
97
+ throw error;
98
+ }
99
+ }
100
+ /**
101
+ * Sidequest 엔진 종료
102
+ */
103
+ async shutdown() {
104
+ if (!this.isStarted) {
105
+ return;
106
+ }
107
+ this.logger.log("Stopping Sidequest engine...");
108
+ try {
109
+ await sidequest.Sidequest.stop();
110
+ this.isStarted = false;
111
+ this.logger.log("Sidequest engine stopped");
112
+ } catch (error) {
113
+ this.logger.error("Failed to stop Sidequest engine", error);
114
+ throw error;
115
+ }
116
+ }
117
+ /**
118
+ * Job 클래스 등록
119
+ */
120
+ registerJob(jobName, JobClass) {
121
+ this.registeredJobs.set(jobName, JobClass);
122
+ this.logger.debug(`Job '${jobName}' registered`);
123
+ }
124
+ /**
125
+ * Job 추가
126
+ */
127
+ async addJob(queueName, jobName, args, options) {
128
+ const JobClass = this.registeredJobs.get(jobName);
129
+ if (!JobClass) {
130
+ throw new Error(`Job class '${jobName}' not found. Make sure it's registered.`);
131
+ }
132
+ let builder = sidequest.Sidequest.build(JobClass).queue(queueName);
133
+ if (options?.maxAttempts !== void 0) {
134
+ builder = builder.maxAttempts(options.maxAttempts);
135
+ }
136
+ if (options?.timeout !== void 0) {
137
+ builder = builder.timeout(options.timeout);
138
+ }
139
+ if (options?.priority !== void 0) ;
140
+ if (options?.scheduledAt !== void 0) {
141
+ builder = builder.availableAt(options.scheduledAt);
142
+ }
143
+ if (options?.retryDelay !== void 0) {
144
+ builder = builder.retryDelay(options.retryDelay);
145
+ }
146
+ if (options?.backoffStrategy !== void 0) {
147
+ builder = builder.backoffStrategy(options.backoffStrategy);
148
+ }
149
+ if (options?.uniqueKey !== void 0) {
150
+ builder = builder.unique(true);
151
+ }
152
+ const jobData = await builder.enqueue(...args);
153
+ const jobId = String(jobData?.id ?? `job_${Date.now()}`);
154
+ this.logger.debug(`Job '${jobName}' (ID: ${jobId}) added to Queue '${queueName}'`);
155
+ return jobId;
156
+ }
157
+ /**
158
+ * Bulk Job 추가
159
+ */
160
+ async addBulkJobs(queueName, jobs) {
161
+ const jobIds = [];
162
+ for (const { jobName, args, options } of jobs) {
163
+ const jobId = await this.addJob(queueName, jobName, args, options);
164
+ jobIds.push(jobId);
165
+ }
166
+ return jobIds;
167
+ }
168
+ /**
169
+ * Job 조회
170
+ */
171
+ async getJob(jobId) {
172
+ try {
173
+ const numericId = typeof jobId === "string" ? parseInt(jobId, 10) : jobId;
174
+ if (isNaN(numericId)) {
175
+ return void 0;
176
+ }
177
+ const job = await sidequest.Sidequest.job.get(numericId);
178
+ if (!job) {
179
+ return void 0;
180
+ }
181
+ const jobData = job;
182
+ return {
183
+ id: String(job.id),
184
+ name: jobData.name,
185
+ queue: job.queue,
186
+ state: job.state,
187
+ attempt: job.attempt,
188
+ maxAttempts: job.max_attempts,
189
+ insertedAt: job.inserted_at,
190
+ attemptedAt: job.attempted_at ?? void 0,
191
+ completedAt: job.completed_at ?? void 0,
192
+ result: job.result,
193
+ errors: job.errors
194
+ };
195
+ } catch {
196
+ return void 0;
197
+ }
198
+ }
199
+ /**
200
+ * 엔진 시작 여부
201
+ */
202
+ get started() {
203
+ return this.isStarted;
204
+ }
205
+ /**
206
+ * 등록된 Job 클래스 반환
207
+ */
208
+ getRegisteredJob(jobName) {
209
+ return this.registeredJobs.get(jobName);
210
+ }
211
+ /**
212
+ * 모든 등록된 Job 클래스 반환
213
+ */
214
+ getAllRegisteredJobs() {
215
+ return this.registeredJobs;
216
+ }
217
+ };
218
+ exports.SidequestAdapter = _ts_decorate([
219
+ common.Injectable()
220
+ ], exports.SidequestAdapter);
221
+ function _ts_decorate2(decorators, target, key, desc) {
222
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
223
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
224
+ 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;
225
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
226
+ }
227
+ __name(_ts_decorate2, "_ts_decorate");
228
+ function _ts_metadata(k, v) {
229
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
230
+ }
231
+ __name(_ts_metadata, "_ts_metadata");
232
+ function _ts_param(paramIndex, decorator) {
233
+ return function(target, key) {
234
+ decorator(target, key, paramIndex);
235
+ };
236
+ }
237
+ __name(_ts_param, "_ts_param");
238
+ exports.SidequestEngineService = class _SidequestEngineService {
239
+ static {
240
+ __name(this, "SidequestEngineService");
241
+ }
242
+ options;
243
+ adapter;
244
+ logger = new common.Logger(_SidequestEngineService.name);
245
+ constructor(options, adapter) {
246
+ this.options = options;
247
+ this.adapter = adapter;
248
+ }
249
+ /**
250
+ * 모듈 초기화 시 엔진 시작
251
+ */
252
+ async onModuleInit() {
253
+ this.logger.log("Initializing Sidequest engine...");
254
+ await this.adapter.start(this.options);
255
+ this.logger.log("Sidequest engine initialized");
256
+ }
257
+ /**
258
+ * 모듈 종료 시 엔진 종료
259
+ */
260
+ async onModuleDestroy() {
261
+ const gracefulShutdown = this.options.gracefulShutdown ?? {
262
+ enabled: true,
263
+ timeout: 3e4
264
+ };
265
+ if (gracefulShutdown.enabled) {
266
+ this.logger.log(`Sidequest engine graceful shutdown (timeout: ${gracefulShutdown.timeout}ms)`);
267
+ }
268
+ await this.adapter.shutdown();
269
+ this.logger.log("Sidequest engine stopped");
270
+ }
271
+ /**
272
+ * 엔진 시작 여부
273
+ */
274
+ get isStarted() {
275
+ return this.adapter.started;
276
+ }
277
+ /**
278
+ * Adapter 인스턴스 반환
279
+ */
280
+ getAdapter() {
281
+ return this.adapter;
282
+ }
283
+ };
284
+ exports.SidequestEngineService = _ts_decorate2([
285
+ common.Injectable(),
286
+ _ts_param(0, common.Inject(SIDEQUEST_MODULE_OPTIONS)),
287
+ _ts_metadata("design:type", Function),
288
+ _ts_metadata("design:paramtypes", [
289
+ typeof SidequestModuleOptions === "undefined" ? Object : SidequestModuleOptions,
290
+ typeof exports.SidequestAdapter === "undefined" ? Object : exports.SidequestAdapter
291
+ ])
292
+ ], exports.SidequestEngineService);
293
+ function _ts_decorate3(decorators, target, key, desc) {
294
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
295
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
296
+ 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;
297
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
298
+ }
299
+ __name(_ts_decorate3, "_ts_decorate");
300
+ function _ts_metadata2(k, v) {
301
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
302
+ }
303
+ __name(_ts_metadata2, "_ts_metadata");
304
+ function _ts_param2(paramIndex, decorator) {
305
+ return function(target, key) {
306
+ decorator(target, key, paramIndex);
307
+ };
308
+ }
309
+ __name(_ts_param2, "_ts_param");
310
+ exports.QueueRegistryService = class _QueueRegistryService {
311
+ static {
312
+ __name(this, "QueueRegistryService");
313
+ }
314
+ options;
315
+ adapter;
316
+ logger = new common.Logger(_QueueRegistryService.name);
317
+ queueServices = /* @__PURE__ */ new Map();
318
+ constructor(options, adapter) {
319
+ this.options = options;
320
+ this.adapter = adapter;
321
+ this.initializeQueues();
322
+ }
323
+ /**
324
+ * 설정된 큐 초기화
325
+ */
326
+ initializeQueues() {
327
+ const queues = this.options.queues ?? [];
328
+ for (const queueConfig of queues) {
329
+ this.registerQueue(queueConfig);
330
+ }
331
+ if (!this.queueServices.has("default")) {
332
+ this.registerQueue({
333
+ name: "default"
334
+ });
335
+ }
336
+ }
337
+ /**
338
+ * 큐 등록
339
+ */
340
+ registerQueue(config) {
341
+ const queueService = this.createQueueService(config.name);
342
+ this.queueServices.set(config.name, queueService);
343
+ this.logger.log(`Queue '${config.name}' registered`);
344
+ }
345
+ /**
346
+ * 큐 서비스 조회
347
+ */
348
+ getQueue(name) {
349
+ return this.queueServices.get(name);
350
+ }
351
+ /**
352
+ * 큐 서비스 조회 (없으면 에러)
353
+ */
354
+ getQueueOrThrow(name) {
355
+ const queue = this.getQueue(name);
356
+ if (!queue) {
357
+ throw new Error(`Queue '${name}' not found. Make sure it is registered in SidequestModule.forRoot().`);
358
+ }
359
+ return queue;
360
+ }
361
+ /**
362
+ * 모든 큐 조회
363
+ */
364
+ getAllQueues() {
365
+ return this.queueServices;
366
+ }
367
+ /**
368
+ * 큐 서비스 인스턴스 생성
369
+ */
370
+ createQueueService(queueName) {
371
+ const adapter = this.adapter;
372
+ return {
373
+ name: queueName,
374
+ async add(JobClass, ...args) {
375
+ const jobName = JobClass.name;
376
+ return adapter.addJob(queueName, jobName, args);
377
+ },
378
+ async addWithOptions(JobClass, options, ...args) {
379
+ const jobName = JobClass.name;
380
+ return adapter.addJob(queueName, jobName, args, options);
381
+ },
382
+ async addScheduled(JobClass, scheduledAt, ...args) {
383
+ const jobName = JobClass.name;
384
+ return adapter.addJob(queueName, jobName, args, {
385
+ scheduledAt
386
+ });
387
+ },
388
+ async addBulk(jobs) {
389
+ const bulkJobs = jobs.map((job) => {
390
+ const result = {
391
+ jobName: job.JobClass.name,
392
+ args: job.args
393
+ };
394
+ if (job.options !== void 0) {
395
+ result.options = job.options;
396
+ }
397
+ return result;
398
+ });
399
+ return adapter.addBulkJobs(queueName, bulkJobs);
400
+ }
401
+ };
402
+ }
403
+ };
404
+ exports.QueueRegistryService = _ts_decorate3([
405
+ common.Injectable(),
406
+ _ts_param2(0, common.Inject(SIDEQUEST_MODULE_OPTIONS)),
407
+ _ts_metadata2("design:type", Function),
408
+ _ts_metadata2("design:paramtypes", [
409
+ typeof SidequestModuleOptions === "undefined" ? Object : SidequestModuleOptions,
410
+ typeof exports.SidequestAdapter === "undefined" ? Object : exports.SidequestAdapter
411
+ ])
412
+ ], exports.QueueRegistryService);
413
+ function _ts_decorate4(decorators, target, key, desc) {
414
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
415
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
416
+ 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;
417
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
418
+ }
419
+ __name(_ts_decorate4, "_ts_decorate");
420
+ function _ts_metadata3(k, v) {
421
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
422
+ }
423
+ __name(_ts_metadata3, "_ts_metadata");
424
+ function _ts_param3(paramIndex, decorator) {
425
+ return function(target, key) {
426
+ decorator(target, key, paramIndex);
427
+ };
428
+ }
429
+ __name(_ts_param3, "_ts_param");
430
+ exports.ClsIntegrationService = class _ClsIntegrationService {
431
+ static {
432
+ __name(this, "ClsIntegrationService");
433
+ }
434
+ logger = new common.Logger(_ClsIntegrationService.name);
435
+ enabled;
436
+ clsService = null;
437
+ constructor(options, clsService) {
438
+ this.enabled = options.enableCls ?? false;
439
+ this.clsService = clsService ?? null;
440
+ if (this.enabled && !this.clsService) {
441
+ this.logger.warn("CLS integration is enabled but nestjs-cls is not installed. Install nestjs-cls to enable context propagation.");
442
+ }
443
+ }
444
+ /**
445
+ * CLS context 내에서 콜백 실행
446
+ */
447
+ async runInContext(metadata, callback) {
448
+ if (!this.enabled || !this.clsService) {
449
+ return callback();
450
+ }
451
+ return new Promise((resolve, reject) => {
452
+ try {
453
+ this.clsService.run(() => {
454
+ for (const [key, value] of Object.entries(metadata)) {
455
+ this.clsService.set(key, value);
456
+ }
457
+ callback().then(resolve).catch(reject);
458
+ });
459
+ } catch (error) {
460
+ reject(error);
461
+ }
462
+ });
463
+ }
464
+ /**
465
+ * 현재 traceId 조회
466
+ */
467
+ getTraceId() {
468
+ if (!this.enabled || !this.clsService) {
469
+ return void 0;
470
+ }
471
+ return this.clsService.get("traceId");
472
+ }
473
+ /**
474
+ * traceId 설정
475
+ */
476
+ setTraceId(traceId) {
477
+ if (!this.enabled || !this.clsService) {
478
+ return;
479
+ }
480
+ this.clsService.set("traceId", traceId);
481
+ }
482
+ /**
483
+ * CLS에서 값 조회
484
+ */
485
+ get(key) {
486
+ if (!this.enabled || !this.clsService) {
487
+ return void 0;
488
+ }
489
+ return this.clsService.get(key);
490
+ }
491
+ /**
492
+ * CLS에 값 설정
493
+ */
494
+ set(key, value) {
495
+ if (!this.enabled || !this.clsService) {
496
+ return;
497
+ }
498
+ this.clsService.set(key, value);
499
+ }
500
+ /**
501
+ * CLS 통합 활성화 여부
502
+ */
503
+ isEnabled() {
504
+ return this.enabled && this.clsService !== null;
505
+ }
506
+ };
507
+ exports.ClsIntegrationService = _ts_decorate4([
508
+ common.Injectable(),
509
+ _ts_param3(0, common.Inject(SIDEQUEST_MODULE_OPTIONS)),
510
+ _ts_param3(1, common.Optional()),
511
+ _ts_param3(1, common.Inject("ClsService")),
512
+ _ts_metadata3("design:type", Function),
513
+ _ts_metadata3("design:paramtypes", [
514
+ typeof SidequestModuleOptions === "undefined" ? Object : SidequestModuleOptions,
515
+ typeof ClsService === "undefined" ? Object : ClsService
516
+ ])
517
+ ], exports.ClsIntegrationService);
518
+
519
+ // src/services/processor-registry.service.ts
520
+ function _ts_decorate5(decorators, target, key, desc) {
521
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
522
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
523
+ 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;
524
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
525
+ }
526
+ __name(_ts_decorate5, "_ts_decorate");
527
+ function _ts_metadata4(k, v) {
528
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
529
+ }
530
+ __name(_ts_metadata4, "_ts_metadata");
531
+ function _ts_param4(paramIndex, decorator) {
532
+ return function(target, key) {
533
+ decorator(target, key, paramIndex);
534
+ };
535
+ }
536
+ __name(_ts_param4, "_ts_param");
537
+ exports.ProcessorRegistryService = class _ProcessorRegistryService {
538
+ static {
539
+ __name(this, "ProcessorRegistryService");
540
+ }
541
+ clsService;
542
+ logger = new common.Logger(_ProcessorRegistryService.name);
543
+ processors = /* @__PURE__ */ new Map();
544
+ constructor(clsService) {
545
+ this.clsService = clsService;
546
+ }
547
+ /**
548
+ * 프로세서 등록
549
+ */
550
+ register(processor) {
551
+ this.processors.set(processor.queueName, processor);
552
+ this.logger.log(`Processor '${processor.metatype.name}' (Queue: ${processor.queueName}) registered`);
553
+ }
554
+ /**
555
+ * 프로세서 조회
556
+ */
557
+ getProcessor(queueName) {
558
+ return this.processors.get(queueName);
559
+ }
560
+ /**
561
+ * 모든 프로세서 조회
562
+ */
563
+ getAllProcessors() {
564
+ return this.processors;
565
+ }
566
+ /**
567
+ * Job 핸들러 조회
568
+ */
569
+ getJobHandler(queueName, jobName) {
570
+ const processor = this.processors.get(queueName);
571
+ if (!processor) {
572
+ return void 0;
573
+ }
574
+ return processor.handlers.get(jobName);
575
+ }
576
+ /**
577
+ * Job 완료 핸들러 조회
578
+ */
579
+ getCompleteHandler(queueName, jobName) {
580
+ const processor = this.processors.get(queueName);
581
+ if (!processor) {
582
+ return void 0;
583
+ }
584
+ return processor.completeHandlers.get(jobName) ?? processor.completeHandlers.get("*");
585
+ }
586
+ /**
587
+ * Job 실패 핸들러 조회
588
+ */
589
+ getFailedHandler(queueName, jobName) {
590
+ const processor = this.processors.get(queueName);
591
+ if (!processor) {
592
+ return void 0;
593
+ }
594
+ return processor.failedHandlers.get(jobName) ?? processor.failedHandlers.get("*");
595
+ }
596
+ /**
597
+ * Job 디스패치 (실행)
598
+ *
599
+ * @param queueName - 큐 이름
600
+ * @param jobName - Job 이름
601
+ * @param args - Job 인자
602
+ * @param metadata - Job 메타데이터 (traceId 등)
603
+ */
604
+ async dispatch(queueName, jobName, args, metadata) {
605
+ const processor = this.processors.get(queueName);
606
+ if (!processor) {
607
+ throw new Error(`Processor not found for Queue '${queueName}'`);
608
+ }
609
+ const handler = processor.handlers.get(jobName);
610
+ if (!handler) {
611
+ throw new Error(`Handler not found for Job '${jobName}' (Queue: ${queueName})`);
612
+ }
613
+ const instance = processor.instance;
614
+ const method = instance[handler.methodName];
615
+ if (typeof method !== "function") {
616
+ throw new Error(`Handler method '${handler.methodName}' not found`);
617
+ }
618
+ const executeJob = /* @__PURE__ */ __name(async () => {
619
+ try {
620
+ const result = await method.apply(processor.instance, args);
621
+ const completeHandlerName = this.getCompleteHandler(queueName, jobName);
622
+ if (completeHandlerName) {
623
+ const completeHandler = instance[completeHandlerName];
624
+ if (typeof completeHandler === "function") {
625
+ await completeHandler.apply(processor.instance, [
626
+ {
627
+ jobName,
628
+ args,
629
+ result
630
+ }
631
+ ]);
632
+ }
633
+ }
634
+ return result;
635
+ } catch (error) {
636
+ const failedHandlerName = this.getFailedHandler(queueName, jobName);
637
+ if (failedHandlerName) {
638
+ const failedHandler = instance[failedHandlerName];
639
+ if (typeof failedHandler === "function") {
640
+ await failedHandler.apply(processor.instance, [
641
+ {
642
+ jobName,
643
+ args,
644
+ error
645
+ }
646
+ ]);
647
+ }
648
+ }
649
+ throw error;
650
+ }
651
+ }, "executeJob");
652
+ if (this.clsService?.isEnabled() && metadata) {
653
+ return this.clsService.runInContext(metadata, executeJob);
654
+ }
655
+ return executeJob();
656
+ }
657
+ };
658
+ exports.ProcessorRegistryService = _ts_decorate5([
659
+ common.Injectable(),
660
+ _ts_param4(0, common.Optional()),
661
+ _ts_metadata4("design:type", Function),
662
+ _ts_metadata4("design:paramtypes", [
663
+ typeof exports.ClsIntegrationService === "undefined" ? Object : exports.ClsIntegrationService
664
+ ])
665
+ ], exports.ProcessorRegistryService);
666
+ function _ts_decorate6(decorators, target, key, desc) {
667
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
668
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
669
+ 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;
670
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
671
+ }
672
+ __name(_ts_decorate6, "_ts_decorate");
673
+ function _ts_metadata5(k, v) {
674
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
675
+ }
676
+ __name(_ts_metadata5, "_ts_metadata");
677
+ var ProcessorExplorer = class _ProcessorExplorer {
678
+ static {
679
+ __name(this, "ProcessorExplorer");
680
+ }
681
+ discoveryService;
682
+ metadataScanner;
683
+ reflector;
684
+ processorRegistry;
685
+ logger = new common.Logger(_ProcessorExplorer.name);
686
+ constructor(discoveryService, metadataScanner, reflector, processorRegistry) {
687
+ this.discoveryService = discoveryService;
688
+ this.metadataScanner = metadataScanner;
689
+ this.reflector = reflector;
690
+ this.processorRegistry = processorRegistry;
691
+ }
692
+ /**
693
+ * 모듈 초기화 시 프로세서 스캔
694
+ */
695
+ async onModuleInit() {
696
+ this.logger.log("Scanning for processors...");
697
+ await this.explore();
698
+ this.logger.log("Processor scan completed");
699
+ }
700
+ /**
701
+ * 모든 프로바이더를 스캔하여 @Processor 클래스 찾기
702
+ */
703
+ async explore() {
704
+ const providers = this.discoveryService.getProviders();
705
+ for (const wrapper of providers) {
706
+ await this.processWrapper(wrapper);
707
+ }
708
+ }
709
+ /**
710
+ * 프로바이더 래퍼 처리
711
+ */
712
+ async processWrapper(wrapper) {
713
+ const { instance, metatype } = wrapper;
714
+ if (!instance || !metatype) {
715
+ return;
716
+ }
717
+ const processorMetadata = this.reflector.get(PROCESSOR_METADATA_KEY, metatype);
718
+ if (!processorMetadata) {
719
+ return;
720
+ }
721
+ const handlers = this.scanHandlers(instance, metatype);
722
+ const completeHandlers = this.scanCompleteHandlers(instance, metatype);
723
+ const failedHandlers = this.scanFailedHandlers(instance, metatype);
724
+ const registeredProcessor = {
725
+ queueName: processorMetadata.queueName,
726
+ instance,
727
+ metatype,
728
+ handlers,
729
+ completeHandlers,
730
+ failedHandlers
731
+ };
732
+ this.processorRegistry.register(registeredProcessor);
733
+ this.logger.log(`Processor '${metatype.name}' registered (Queue: ${processorMetadata.queueName}, Handlers: ${handlers.size})`);
734
+ }
735
+ /**
736
+ * @OnJob 메서드 스캔
737
+ */
738
+ scanHandlers(instance, _metatype) {
739
+ const handlers = /* @__PURE__ */ new Map();
740
+ const prototype = Object.getPrototypeOf(instance);
741
+ const methodNames = this.metadataScanner.getAllMethodNames(prototype);
742
+ for (const methodName of methodNames) {
743
+ const methodRef = prototype[methodName];
744
+ const onJobMetadata = this.reflector.get(ON_JOB_METADATA_KEY, methodRef);
745
+ if (!onJobMetadata) {
746
+ continue;
747
+ }
748
+ const retryOptions = this.reflector.get(RETRY_OPTIONS_METADATA_KEY, methodRef);
749
+ const handler = {
750
+ methodName,
751
+ jobName: onJobMetadata.jobName,
752
+ options: onJobMetadata.options,
753
+ retryOptions
754
+ };
755
+ handlers.set(onJobMetadata.jobName, handler);
756
+ this.logger.debug(` - Job '${onJobMetadata.jobName}' -> ${methodName}()`);
757
+ }
758
+ return handlers;
759
+ }
760
+ /**
761
+ * @OnJobComplete 메서드 스캔
762
+ */
763
+ scanCompleteHandlers(instance, _metatype) {
764
+ const handlers = /* @__PURE__ */ new Map();
765
+ const prototype = Object.getPrototypeOf(instance);
766
+ const methodNames = this.metadataScanner.getAllMethodNames(prototype);
767
+ for (const methodName of methodNames) {
768
+ const methodRef = prototype[methodName];
769
+ const jobName = this.reflector.get(ON_JOB_COMPLETE_METADATA_KEY, methodRef);
770
+ if (jobName !== void 0) {
771
+ const key = jobName || "*";
772
+ handlers.set(key, methodName);
773
+ this.logger.debug(` - OnJobComplete '${key}' -> ${methodName}()`);
774
+ }
775
+ }
776
+ return handlers;
777
+ }
778
+ /**
779
+ * @OnJobFailed 메서드 스캔
780
+ */
781
+ scanFailedHandlers(instance, _metatype) {
782
+ const handlers = /* @__PURE__ */ new Map();
783
+ const prototype = Object.getPrototypeOf(instance);
784
+ const methodNames = this.metadataScanner.getAllMethodNames(prototype);
785
+ for (const methodName of methodNames) {
786
+ const methodRef = prototype[methodName];
787
+ const jobName = this.reflector.get(ON_JOB_FAILED_METADATA_KEY, methodRef);
788
+ if (jobName !== void 0) {
789
+ const key = jobName || "*";
790
+ handlers.set(key, methodName);
791
+ this.logger.debug(` - OnJobFailed '${key}' -> ${methodName}()`);
792
+ }
793
+ }
794
+ return handlers;
795
+ }
796
+ };
797
+ ProcessorExplorer = _ts_decorate6([
798
+ common.Injectable(),
799
+ _ts_metadata5("design:type", Function),
800
+ _ts_metadata5("design:paramtypes", [
801
+ typeof core.DiscoveryService === "undefined" ? Object : core.DiscoveryService,
802
+ typeof core.MetadataScanner === "undefined" ? Object : core.MetadataScanner,
803
+ typeof core.Reflector === "undefined" ? Object : core.Reflector,
804
+ typeof exports.ProcessorRegistryService === "undefined" ? Object : exports.ProcessorRegistryService
805
+ ])
806
+ ], ProcessorExplorer);
807
+
808
+ // src/modules/sidequest.module.ts
809
+ function _ts_decorate7(decorators, target, key, desc) {
810
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
811
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
812
+ 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;
813
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
814
+ }
815
+ __name(_ts_decorate7, "_ts_decorate");
816
+ exports.SidequestModule = class _SidequestModule {
817
+ static {
818
+ __name(this, "SidequestModule");
819
+ }
820
+ /**
821
+ * 동기 설정으로 모듈 등록
822
+ */
823
+ static forRoot(options) {
824
+ const isGlobal = options.isGlobal ?? true;
825
+ const queueProviders = this.createQueueProviders(options);
826
+ return {
827
+ module: _SidequestModule,
828
+ global: isGlobal,
829
+ imports: [
830
+ core.DiscoveryModule
831
+ ],
832
+ providers: [
833
+ {
834
+ provide: SIDEQUEST_MODULE_OPTIONS,
835
+ useValue: options
836
+ },
837
+ exports.SidequestAdapter,
838
+ exports.SidequestEngineService,
839
+ exports.QueueRegistryService,
840
+ exports.ProcessorRegistryService,
841
+ exports.ClsIntegrationService,
842
+ ProcessorExplorer,
843
+ ...queueProviders
844
+ ],
845
+ exports: [
846
+ SIDEQUEST_MODULE_OPTIONS,
847
+ exports.SidequestAdapter,
848
+ exports.SidequestEngineService,
849
+ exports.QueueRegistryService,
850
+ exports.ProcessorRegistryService,
851
+ exports.ClsIntegrationService,
852
+ ...queueProviders.map((p) => p.provide)
853
+ ]
854
+ };
855
+ }
856
+ /**
857
+ * 비동기 설정으로 모듈 등록
858
+ */
859
+ static forRootAsync(asyncOptions) {
860
+ const isGlobal = asyncOptions.isGlobal ?? true;
861
+ return {
862
+ module: _SidequestModule,
863
+ global: isGlobal,
864
+ imports: [
865
+ core.DiscoveryModule,
866
+ ...asyncOptions.imports || []
867
+ ],
868
+ providers: [
869
+ ...this.createAsyncProviders(asyncOptions),
870
+ exports.SidequestAdapter,
871
+ exports.SidequestEngineService,
872
+ exports.QueueRegistryService,
873
+ exports.ProcessorRegistryService,
874
+ exports.ClsIntegrationService,
875
+ ProcessorExplorer,
876
+ // 동적 큐 프로바이더 - options에서 queues를 읽어 생성
877
+ {
878
+ provide: "SIDEQUEST_QUEUE_PROVIDERS_INIT",
879
+ useFactory: /* @__PURE__ */ __name(() => {
880
+ return true;
881
+ }, "useFactory"),
882
+ inject: [
883
+ exports.QueueRegistryService
884
+ ]
885
+ }
886
+ ],
887
+ exports: [
888
+ SIDEQUEST_MODULE_OPTIONS,
889
+ exports.SidequestAdapter,
890
+ exports.SidequestEngineService,
891
+ exports.QueueRegistryService,
892
+ exports.ProcessorRegistryService,
893
+ exports.ClsIntegrationService
894
+ ]
895
+ };
896
+ }
897
+ /**
898
+ * 큐별 DI 프로바이더 생성
899
+ */
900
+ static createQueueProviders(options) {
901
+ const queues = options.queues ?? [
902
+ {
903
+ name: "default"
904
+ }
905
+ ];
906
+ return queues.map((queue) => ({
907
+ provide: getQueueToken(queue.name),
908
+ useFactory: /* @__PURE__ */ __name((registry) => registry.getQueueOrThrow(queue.name), "useFactory"),
909
+ inject: [
910
+ exports.QueueRegistryService
911
+ ]
912
+ }));
913
+ }
914
+ /**
915
+ * 비동기 프로바이더 생성
916
+ */
917
+ static createAsyncProviders(asyncOptions) {
918
+ if (asyncOptions.useFactory) {
919
+ return [
920
+ {
921
+ provide: SIDEQUEST_MODULE_OPTIONS,
922
+ useFactory: asyncOptions.useFactory,
923
+ inject: asyncOptions.inject || []
924
+ }
925
+ ];
926
+ }
927
+ if (asyncOptions.useClass) {
928
+ return [
929
+ {
930
+ provide: asyncOptions.useClass,
931
+ useClass: asyncOptions.useClass
932
+ },
933
+ {
934
+ provide: SIDEQUEST_MODULE_OPTIONS,
935
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => optionsFactory.createSidequestOptions(), "useFactory"),
936
+ inject: [
937
+ asyncOptions.useClass
938
+ ]
939
+ }
940
+ ];
941
+ }
942
+ if (asyncOptions.useExisting) {
943
+ return [
944
+ {
945
+ provide: SIDEQUEST_MODULE_OPTIONS,
946
+ useFactory: /* @__PURE__ */ __name(async (optionsFactory) => optionsFactory.createSidequestOptions(), "useFactory"),
947
+ inject: [
948
+ asyncOptions.useExisting
949
+ ]
950
+ }
951
+ ];
952
+ }
953
+ return [
954
+ {
955
+ provide: SIDEQUEST_MODULE_OPTIONS,
956
+ useValue: {}
957
+ }
958
+ ];
959
+ }
960
+ };
961
+ exports.SidequestModule = _ts_decorate7([
962
+ common.Global(),
963
+ common.Module({})
964
+ ], exports.SidequestModule);
965
+ function Processor(queueName, options) {
966
+ return (target) => {
967
+ const metadata = {
968
+ queueName,
969
+ options
970
+ };
971
+ common.SetMetadata(PROCESSOR_METADATA_KEY, metadata)(target);
972
+ common.Injectable()(target);
973
+ };
974
+ }
975
+ __name(Processor, "Processor");
976
+ function OnJob(jobName, options) {
977
+ return (target, propertyKey, descriptor) => {
978
+ const metadata = {
979
+ jobName,
980
+ options
981
+ };
982
+ common.SetMetadata(ON_JOB_METADATA_KEY, metadata)(target, propertyKey, descriptor);
983
+ return descriptor;
984
+ };
985
+ }
986
+ __name(OnJob, "OnJob");
987
+ function Retry(options) {
988
+ return (target, propertyKey, descriptor) => {
989
+ common.SetMetadata(RETRY_OPTIONS_METADATA_KEY, options)(target, propertyKey, descriptor);
990
+ return descriptor;
991
+ };
992
+ }
993
+ __name(Retry, "Retry");
994
+ function InjectQueue(queueName) {
995
+ return common.Inject(getQueueToken(queueName));
996
+ }
997
+ __name(InjectQueue, "InjectQueue");
998
+ function OnJobComplete(jobName) {
999
+ return (target, propertyKey, descriptor) => {
1000
+ common.SetMetadata(ON_JOB_COMPLETE_METADATA_KEY, jobName ?? "")(target, propertyKey, descriptor);
1001
+ return descriptor;
1002
+ };
1003
+ }
1004
+ __name(OnJobComplete, "OnJobComplete");
1005
+ function OnJobFailed(jobName) {
1006
+ return (target, propertyKey, descriptor) => {
1007
+ common.SetMetadata(ON_JOB_FAILED_METADATA_KEY, jobName ?? "")(target, propertyKey, descriptor);
1008
+ return descriptor;
1009
+ };
1010
+ }
1011
+ __name(OnJobFailed, "OnJobFailed");
1012
+
1013
+ Object.defineProperty(exports, "Job", {
1014
+ enumerable: true,
1015
+ get: function () { return sidequest.Job; }
1016
+ });
1017
+ exports.DEFAULT_CONCURRENCY = DEFAULT_CONCURRENCY;
1018
+ exports.DEFAULT_MAX_ATTEMPTS = DEFAULT_MAX_ATTEMPTS;
1019
+ exports.DEFAULT_QUEUE_NAME = DEFAULT_QUEUE_NAME;
1020
+ exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
1021
+ exports.InjectQueue = InjectQueue;
1022
+ exports.ON_JOB_COMPLETE_METADATA_KEY = ON_JOB_COMPLETE_METADATA_KEY;
1023
+ exports.ON_JOB_FAILED_METADATA_KEY = ON_JOB_FAILED_METADATA_KEY;
1024
+ exports.ON_JOB_METADATA_KEY = ON_JOB_METADATA_KEY;
1025
+ exports.OnJob = OnJob;
1026
+ exports.OnJobComplete = OnJobComplete;
1027
+ exports.OnJobFailed = OnJobFailed;
1028
+ exports.PROCESSOR_METADATA_KEY = PROCESSOR_METADATA_KEY;
1029
+ exports.Processor = Processor;
1030
+ exports.QUEUE_TOKEN_PREFIX = QUEUE_TOKEN_PREFIX;
1031
+ exports.RETRY_OPTIONS_METADATA_KEY = RETRY_OPTIONS_METADATA_KEY;
1032
+ exports.Retry = Retry;
1033
+ exports.SIDEQUEST_ENGINE = SIDEQUEST_ENGINE;
1034
+ exports.SIDEQUEST_MODULE_OPTIONS = SIDEQUEST_MODULE_OPTIONS;
1035
+ exports.getQueueToken = getQueueToken;
1036
+ //# sourceMappingURL=index.cjs.map
1037
+ //# sourceMappingURL=index.cjs.map