@monque/tsed 0.1.0 → 1.0.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/README.md +18 -18
- package/dist/CHANGELOG.md +19 -0
- package/dist/README.md +18 -18
- package/dist/index.cjs +101 -88
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -63
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +78 -64
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +98 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/config/config.ts +4 -2
- package/src/config/types.ts +35 -2
- package/src/constants/constants.ts +1 -1
- package/src/constants/types.ts +3 -3
- package/src/decorators/cron.ts +5 -5
- package/src/decorators/index.ts +5 -5
- package/src/decorators/{worker-controller.ts → job-controller.ts} +14 -14
- package/src/decorators/{worker.ts → job.ts} +14 -14
- package/src/decorators/types.ts +18 -18
- package/src/index.ts +7 -7
- package/src/monque-module.ts +23 -18
- package/src/utils/build-job-name.ts +2 -2
- package/src/utils/collect-job-metadata.ts +95 -0
- package/src/utils/get-job-token.ts +29 -0
- package/src/utils/index.ts +4 -4
- package/src/utils/resolve-database.ts +6 -5
- package/src/utils/collect-worker-metadata.ts +0 -95
- package/src/utils/get-worker-token.ts +0 -27
package/README.md
CHANGED
|
@@ -26,8 +26,8 @@ A **Ts.ED** integration for **Monque**, a robust, type-safe MongoDB job queue fo
|
|
|
26
26
|
|
|
27
27
|
## Features
|
|
28
28
|
|
|
29
|
-
- 🎯 **Decorator-based API**: `@
|
|
30
|
-
- 💉 **Dependency Injection**: Full support for Ts.ED DI (inject Services/Providers into your
|
|
29
|
+
- 🎯 **Decorator-based API**: `@JobController`, `@Job`, and `@Cron` for declarative job handling.
|
|
30
|
+
- 💉 **Dependency Injection**: Full support for Ts.ED DI (inject Services/Providers into your jobs).
|
|
31
31
|
- 🔒 **Job Isolation**: Each job execution runs in a dedicated `DIContext` with Request Scope support.
|
|
32
32
|
- 🔍 **Type Safety**: Leverage TypeScript generics for fully typed job payloads.
|
|
33
33
|
- ⚡ **Full Monque Power**: Complete access to all `@monque/core` features (backoff, heartbeats, atomic locking).
|
|
@@ -85,13 +85,13 @@ export class Server {}
|
|
|
85
85
|
|
|
86
86
|
## Usage
|
|
87
87
|
|
|
88
|
-
### 1. Define a
|
|
88
|
+
### 1. Define a Job Controller
|
|
89
89
|
|
|
90
|
-
Create a class decorated with `@
|
|
90
|
+
Create a class decorated with `@JobController`. Methods decorated with `@Job` will process jobs.
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
|
-
import {
|
|
94
|
-
import { Job } from "@monque/core";
|
|
93
|
+
import { JobController, Job } from "@monque/tsed";
|
|
94
|
+
import { Job as MonqueJob } from "@monque/core";
|
|
95
95
|
import { EmailService } from "./services/EmailService";
|
|
96
96
|
|
|
97
97
|
interface EmailPayload {
|
|
@@ -99,12 +99,12 @@ interface EmailPayload {
|
|
|
99
99
|
subject: string;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
@
|
|
103
|
-
export class
|
|
102
|
+
@JobController("email") // Namespace prefix: "email."
|
|
103
|
+
export class EmailJobs {
|
|
104
104
|
constructor(private emailService: EmailService) {}
|
|
105
105
|
|
|
106
|
-
@
|
|
107
|
-
async sendEmail(job:
|
|
106
|
+
@Job("send", { concurrency: 5 }) // Job name: "email.send"
|
|
107
|
+
async sendEmail(job: MonqueJob<EmailPayload>) {
|
|
108
108
|
await this.emailService.send(
|
|
109
109
|
job.data.to,
|
|
110
110
|
job.data.subject
|
|
@@ -118,10 +118,10 @@ export class EmailWorkers {
|
|
|
118
118
|
Use the `@Cron` decorator to schedule recurring tasks.
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
|
-
import {
|
|
121
|
+
import { JobController, Cron } from "@monque/tsed";
|
|
122
122
|
|
|
123
|
-
@
|
|
124
|
-
export class
|
|
123
|
+
@JobController()
|
|
124
|
+
export class ReportJobs {
|
|
125
125
|
|
|
126
126
|
@Cron("0 0 * * *", { name: "daily-report" })
|
|
127
127
|
async generateDailyReport() {
|
|
@@ -159,11 +159,11 @@ export class AuthService {
|
|
|
159
159
|
|
|
160
160
|
### Decorators
|
|
161
161
|
|
|
162
|
-
#### `@
|
|
163
|
-
Class decorator to register a
|
|
164
|
-
- `namespace`: Optional prefix for all
|
|
162
|
+
#### `@JobController(namespace?: string)`
|
|
163
|
+
Class decorator to register a job controller.
|
|
164
|
+
- `namespace`: Optional prefix for all job names in this class.
|
|
165
165
|
|
|
166
|
-
#### `@
|
|
166
|
+
#### `@Job(name: string, options?: WorkerOptions)`
|
|
167
167
|
Method decorator to register a job handler.
|
|
168
168
|
- `name`: Job name (combined with namespace).
|
|
169
169
|
- `options`: Supports all `@monque/core` [WorkerOptions](../../packages/core/README.md#new-monque-db-options) (concurrency, lockTimeout, etc.).
|
|
@@ -206,7 +206,7 @@ Use `@tsed/platform-http/testing` and `PlatformTest` to test your workers. You c
|
|
|
206
206
|
import { PlatformTest } from "@tsed/platform-http/testing";
|
|
207
207
|
import { MonqueService } from "@monque/tsed";
|
|
208
208
|
|
|
209
|
-
describe("
|
|
209
|
+
describe("EmailJobs", () => {
|
|
210
210
|
beforeEach(PlatformTest.create);
|
|
211
211
|
afterEach(PlatformTest.reset);
|
|
212
212
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @monque/tsed
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#113](https://github.com/ueberBrot/monque/pull/113) [`94a25d0`](https://github.com/ueberBrot/monque/commit/94a25d0f64f394af72c06a5457db5431df996c45) Thanks [@ueberBrot](https://github.com/ueberBrot)! - Rename `@Worker` and `@WorkerController` to `@Job` and `@JobController`.
|
|
8
|
+
|
|
9
|
+
This is a breaking change that aligns the terminology with the core package and general job queue conventions.
|
|
10
|
+
|
|
11
|
+
- Renamed `@Worker` decorator to `@Job`
|
|
12
|
+
- Renamed `@WorkerController` decorator to `@JobController`
|
|
13
|
+
- Renamed internal metadata types and store keys to use "Job" instead of "Worker" (e.g., `JobStore`, `JobMetadata`)
|
|
14
|
+
- Updated logging and constants to reflect the change
|
|
15
|
+
- Added `disableJobProcessing` option to run Ts.ED instances in producer-only mode. When enabled, the instance can enqueue jobs and manage schedules but will not process any jobs.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`9b7f44f`](https://github.com/ueberBrot/monque/commit/9b7f44f5c1f6b4aa4215e571189cc03cbaa49865)]:
|
|
20
|
+
- @monque/core@1.2.0
|
|
21
|
+
|
|
3
22
|
## 0.1.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/README.md
CHANGED
|
@@ -26,8 +26,8 @@ A **Ts.ED** integration for **Monque**, a robust, type-safe MongoDB job queue fo
|
|
|
26
26
|
|
|
27
27
|
## Features
|
|
28
28
|
|
|
29
|
-
- 🎯 **Decorator-based API**: `@
|
|
30
|
-
- 💉 **Dependency Injection**: Full support for Ts.ED DI (inject Services/Providers into your
|
|
29
|
+
- 🎯 **Decorator-based API**: `@JobController`, `@Job`, and `@Cron` for declarative job handling.
|
|
30
|
+
- 💉 **Dependency Injection**: Full support for Ts.ED DI (inject Services/Providers into your jobs).
|
|
31
31
|
- 🔒 **Job Isolation**: Each job execution runs in a dedicated `DIContext` with Request Scope support.
|
|
32
32
|
- 🔍 **Type Safety**: Leverage TypeScript generics for fully typed job payloads.
|
|
33
33
|
- ⚡ **Full Monque Power**: Complete access to all `@monque/core` features (backoff, heartbeats, atomic locking).
|
|
@@ -85,13 +85,13 @@ export class Server {}
|
|
|
85
85
|
|
|
86
86
|
## Usage
|
|
87
87
|
|
|
88
|
-
### 1. Define a
|
|
88
|
+
### 1. Define a Job Controller
|
|
89
89
|
|
|
90
|
-
Create a class decorated with `@
|
|
90
|
+
Create a class decorated with `@JobController`. Methods decorated with `@Job` will process jobs.
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
|
-
import {
|
|
94
|
-
import { Job } from "@monque/core";
|
|
93
|
+
import { JobController, Job } from "@monque/tsed";
|
|
94
|
+
import { Job as MonqueJob } from "@monque/core";
|
|
95
95
|
import { EmailService } from "./services/EmailService";
|
|
96
96
|
|
|
97
97
|
interface EmailPayload {
|
|
@@ -99,12 +99,12 @@ interface EmailPayload {
|
|
|
99
99
|
subject: string;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
@
|
|
103
|
-
export class
|
|
102
|
+
@JobController("email") // Namespace prefix: "email."
|
|
103
|
+
export class EmailJobs {
|
|
104
104
|
constructor(private emailService: EmailService) {}
|
|
105
105
|
|
|
106
|
-
@
|
|
107
|
-
async sendEmail(job:
|
|
106
|
+
@Job("send", { concurrency: 5 }) // Job name: "email.send"
|
|
107
|
+
async sendEmail(job: MonqueJob<EmailPayload>) {
|
|
108
108
|
await this.emailService.send(
|
|
109
109
|
job.data.to,
|
|
110
110
|
job.data.subject
|
|
@@ -118,10 +118,10 @@ export class EmailWorkers {
|
|
|
118
118
|
Use the `@Cron` decorator to schedule recurring tasks.
|
|
119
119
|
|
|
120
120
|
```typescript
|
|
121
|
-
import {
|
|
121
|
+
import { JobController, Cron } from "@monque/tsed";
|
|
122
122
|
|
|
123
|
-
@
|
|
124
|
-
export class
|
|
123
|
+
@JobController()
|
|
124
|
+
export class ReportJobs {
|
|
125
125
|
|
|
126
126
|
@Cron("0 0 * * *", { name: "daily-report" })
|
|
127
127
|
async generateDailyReport() {
|
|
@@ -159,11 +159,11 @@ export class AuthService {
|
|
|
159
159
|
|
|
160
160
|
### Decorators
|
|
161
161
|
|
|
162
|
-
#### `@
|
|
163
|
-
Class decorator to register a
|
|
164
|
-
- `namespace`: Optional prefix for all
|
|
162
|
+
#### `@JobController(namespace?: string)`
|
|
163
|
+
Class decorator to register a job controller.
|
|
164
|
+
- `namespace`: Optional prefix for all job names in this class.
|
|
165
165
|
|
|
166
|
-
#### `@
|
|
166
|
+
#### `@Job(name: string, options?: WorkerOptions)`
|
|
167
167
|
Method decorator to register a job handler.
|
|
168
168
|
- `name`: Job name (combined with namespace).
|
|
169
169
|
- `options`: Supports all `@monque/core` [WorkerOptions](../../packages/core/README.md#new-monque-db-options) (concurrency, lockTimeout, etc.).
|
|
@@ -206,7 +206,7 @@ Use `@tsed/platform-http/testing` and `PlatformTest` to test your workers. You c
|
|
|
206
206
|
import { PlatformTest } from "@tsed/platform-http/testing";
|
|
207
207
|
import { MonqueService } from "@monque/tsed";
|
|
208
208
|
|
|
209
|
-
describe("
|
|
209
|
+
describe("EmailJobs", () => {
|
|
210
210
|
beforeEach(PlatformTest.create);
|
|
211
211
|
afterEach(PlatformTest.reset);
|
|
212
212
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
let _monque_core = require("@monque/core");
|
|
1
2
|
let _tsed_core = require("@tsed/core");
|
|
2
3
|
let _tsed_di = require("@tsed/di");
|
|
3
|
-
let _monque_core = require("@monque/core");
|
|
4
4
|
let mongodb = require("mongodb");
|
|
5
5
|
|
|
6
6
|
//#region src/config/config.ts
|
|
7
7
|
/**
|
|
8
|
+
* @monque/tsed - Configuration
|
|
9
|
+
*
|
|
10
|
+
* Defines the configuration interface and TsED module augmentation.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
8
13
|
* Validate that exactly one database resolution strategy is provided.
|
|
9
14
|
*
|
|
10
15
|
* @param config - The configuration to validate.
|
|
@@ -23,8 +28,8 @@ function validateDatabaseConfig(config) {
|
|
|
23
28
|
config.dbFactory,
|
|
24
29
|
config.dbToken
|
|
25
30
|
].filter(Boolean);
|
|
26
|
-
if (strategies.length === 0) throw new
|
|
27
|
-
if (strategies.length > 1) throw new
|
|
31
|
+
if (strategies.length === 0) throw new _monque_core.MonqueError("MonqueTsedConfig requires exactly one of 'db', 'dbFactory', or 'dbToken' to be set");
|
|
32
|
+
if (strategies.length > 1) throw new _monque_core.MonqueError("MonqueTsedConfig accepts only one of 'db', 'dbFactory', or 'dbToken' - multiple were provided");
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
//#endregion
|
|
@@ -32,7 +37,7 @@ function validateDatabaseConfig(config) {
|
|
|
32
37
|
/**
|
|
33
38
|
* Symbol used to store decorator metadata on class constructors.
|
|
34
39
|
*
|
|
35
|
-
* Used by @
|
|
40
|
+
* Used by @JobController, @Job, and @Cron decorators to attach
|
|
36
41
|
* metadata that is later collected by MonqueModule during initialization.
|
|
37
42
|
*
|
|
38
43
|
* @example
|
|
@@ -49,13 +54,13 @@ const MONQUE = Symbol.for("monque");
|
|
|
49
54
|
*
|
|
50
55
|
* These constants are used to categorize providers registered with Ts.ED's
|
|
51
56
|
* dependency injection container, enabling MonqueModule to discover and
|
|
52
|
-
* register
|
|
57
|
+
* register jobs automatically.
|
|
53
58
|
*
|
|
54
59
|
* Note: Using string constants with `as const` instead of enums per
|
|
55
60
|
* Constitution guidelines.
|
|
56
61
|
*/
|
|
57
62
|
const ProviderTypes = {
|
|
58
|
-
|
|
63
|
+
JOB_CONTROLLER: "monque:job-controller",
|
|
59
64
|
CRON: "monque:cron"
|
|
60
65
|
};
|
|
61
66
|
|
|
@@ -69,8 +74,8 @@ const ProviderTypes = {
|
|
|
69
74
|
*
|
|
70
75
|
* @example
|
|
71
76
|
* ```typescript
|
|
72
|
-
* @
|
|
73
|
-
* class
|
|
77
|
+
* @JobController()
|
|
78
|
+
* class ReportJobs {
|
|
74
79
|
* @Cron("@daily", { timezone: "UTC" })
|
|
75
80
|
* async generateDailyReport() {
|
|
76
81
|
* // ...
|
|
@@ -91,7 +96,7 @@ function Cron(pattern, options) {
|
|
|
91
96
|
const store = _tsed_core.Store.from(targetConstructor);
|
|
92
97
|
const existing = store.get(MONQUE) || {
|
|
93
98
|
type: "controller",
|
|
94
|
-
|
|
99
|
+
jobs: [],
|
|
95
100
|
cronJobs: []
|
|
96
101
|
};
|
|
97
102
|
const cronJobs = [...existing.cronJobs || [], cronMetadata];
|
|
@@ -103,21 +108,21 @@ function Cron(pattern, options) {
|
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
//#endregion
|
|
106
|
-
//#region src/decorators/
|
|
111
|
+
//#region src/decorators/job.ts
|
|
107
112
|
/**
|
|
108
|
-
* @
|
|
113
|
+
* @Job method decorator
|
|
109
114
|
*
|
|
110
115
|
* Registers a method as a job handler. The method will be called when a job
|
|
111
116
|
* with the matching name is picked up for processing.
|
|
112
117
|
*
|
|
113
118
|
* @param name - Job name (combined with controller namespace if present).
|
|
114
|
-
* @param options -
|
|
119
|
+
* @param options - Job configuration options.
|
|
115
120
|
*
|
|
116
121
|
* @example
|
|
117
122
|
* ```typescript
|
|
118
|
-
* @
|
|
119
|
-
* export class
|
|
120
|
-
* @
|
|
123
|
+
* @JobController("notifications")
|
|
124
|
+
* export class NotificationJobs {
|
|
125
|
+
* @Job("push", { concurrency: 10 })
|
|
121
126
|
* async sendPush(job: Job<PushPayload>) {
|
|
122
127
|
* await pushService.send(job.data);
|
|
123
128
|
* }
|
|
@@ -128,11 +133,11 @@ function Cron(pattern, options) {
|
|
|
128
133
|
* Method decorator that registers a method as a job handler.
|
|
129
134
|
*
|
|
130
135
|
* @param name - The job name (will be prefixed with controller namespace if present)
|
|
131
|
-
* @param options - Optional
|
|
136
|
+
* @param options - Optional job configuration (concurrency, replace, etc.)
|
|
132
137
|
*/
|
|
133
|
-
function
|
|
138
|
+
function Job(name, options) {
|
|
134
139
|
return (target, propertyKey, _descriptor) => {
|
|
135
|
-
const
|
|
140
|
+
const jobMetadata = {
|
|
136
141
|
name,
|
|
137
142
|
method: String(propertyKey),
|
|
138
143
|
opts: options || {}
|
|
@@ -141,53 +146,53 @@ function Worker(name, options) {
|
|
|
141
146
|
const store = _tsed_core.Store.from(targetConstructor);
|
|
142
147
|
const existing = store.get(MONQUE) || {
|
|
143
148
|
type: "controller",
|
|
144
|
-
|
|
149
|
+
jobs: [],
|
|
145
150
|
cronJobs: []
|
|
146
151
|
};
|
|
147
|
-
const
|
|
152
|
+
const jobs = [...existing.jobs || [], jobMetadata];
|
|
148
153
|
store.set(MONQUE, {
|
|
149
154
|
...existing,
|
|
150
|
-
|
|
155
|
+
jobs
|
|
151
156
|
});
|
|
152
157
|
};
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
//#endregion
|
|
156
|
-
//#region src/decorators/
|
|
161
|
+
//#region src/decorators/job-controller.ts
|
|
157
162
|
/**
|
|
158
|
-
* @
|
|
163
|
+
* @JobController class decorator
|
|
159
164
|
*
|
|
160
|
-
* Marks a class as containing
|
|
161
|
-
*
|
|
165
|
+
* Marks a class as containing job methods and registers it with the Ts.ED DI container.
|
|
166
|
+
* Jobs in the class will have their job names prefixed with the namespace.
|
|
162
167
|
*
|
|
163
168
|
* @param namespace - Optional prefix for all job names in this controller.
|
|
164
169
|
* When set, job names become "{namespace}.{name}".
|
|
165
170
|
*
|
|
166
171
|
* @example
|
|
167
172
|
* ```typescript
|
|
168
|
-
* @
|
|
169
|
-
* export class
|
|
170
|
-
* @
|
|
173
|
+
* @JobController("email")
|
|
174
|
+
* export class EmailJobs {
|
|
175
|
+
* @Job("send") // Registered as "email.send"
|
|
171
176
|
* async send(job: Job<EmailPayload>) { }
|
|
172
177
|
* }
|
|
173
178
|
* ```
|
|
174
179
|
*/
|
|
175
180
|
/**
|
|
176
|
-
* Class decorator that registers a class as a
|
|
181
|
+
* Class decorator that registers a class as a job controller.
|
|
177
182
|
*
|
|
178
183
|
* @param namespace - Optional namespace prefix for job names
|
|
179
184
|
*/
|
|
180
|
-
function
|
|
181
|
-
return (0, _tsed_core.useDecorators)((0, _tsed_di.Injectable)({ type: ProviderTypes.
|
|
185
|
+
function JobController(namespace) {
|
|
186
|
+
return (0, _tsed_core.useDecorators)((0, _tsed_di.Injectable)({ type: ProviderTypes.JOB_CONTROLLER }), (target) => {
|
|
182
187
|
const store = _tsed_core.Store.from(target);
|
|
183
188
|
const existing = store.get(MONQUE) || {};
|
|
184
|
-
const
|
|
189
|
+
const jobStore = {
|
|
185
190
|
type: "controller",
|
|
186
191
|
...namespace !== void 0 && { namespace },
|
|
187
|
-
|
|
192
|
+
jobs: existing.jobs || [],
|
|
188
193
|
cronJobs: existing.cronJobs || []
|
|
189
194
|
};
|
|
190
|
-
store.set(MONQUE,
|
|
195
|
+
store.set(MONQUE, jobStore);
|
|
191
196
|
});
|
|
192
197
|
}
|
|
193
198
|
|
|
@@ -379,8 +384,8 @@ MonqueService = __decorate([(0, _tsed_di.Injectable)()], MonqueService);
|
|
|
379
384
|
/**
|
|
380
385
|
* Build the full job name by combining namespace and name.
|
|
381
386
|
*
|
|
382
|
-
* @param namespace - Optional namespace from @
|
|
383
|
-
* @param name - Job name from @
|
|
387
|
+
* @param namespace - Optional namespace from @JobController
|
|
388
|
+
* @param name - Job name from @Job or @Cron
|
|
384
389
|
* @returns Full job name (e.g., "email.send" or just "send")
|
|
385
390
|
*
|
|
386
391
|
* @example
|
|
@@ -395,22 +400,22 @@ function buildJobName(namespace, name) {
|
|
|
395
400
|
}
|
|
396
401
|
|
|
397
402
|
//#endregion
|
|
398
|
-
//#region src/utils/collect-
|
|
403
|
+
//#region src/utils/collect-job-metadata.ts
|
|
399
404
|
/**
|
|
400
|
-
* Collect
|
|
405
|
+
* Collect job metadata utility
|
|
401
406
|
*
|
|
402
|
-
* Collects all
|
|
403
|
-
* Used by MonqueModule to discover and register all
|
|
407
|
+
* Collects all job metadata from a class decorated with @JobController.
|
|
408
|
+
* Used by MonqueModule to discover and register all jobs.
|
|
404
409
|
*/
|
|
405
410
|
/**
|
|
406
|
-
* Collect all
|
|
411
|
+
* Collect all job metadata from a class.
|
|
407
412
|
*
|
|
408
|
-
* @param target - The class constructor (decorated with @
|
|
409
|
-
* @returns Array of collected
|
|
413
|
+
* @param target - The class constructor (decorated with @JobController)
|
|
414
|
+
* @returns Array of collected job metadata ready for registration
|
|
410
415
|
*
|
|
411
416
|
* @example
|
|
412
417
|
* ```typescript
|
|
413
|
-
* const metadata =
|
|
418
|
+
* const metadata = collectJobMetadata(EmailJobs);
|
|
414
419
|
* // Returns:
|
|
415
420
|
* // [
|
|
416
421
|
* // { fullName: "email.send", method: "sendEmail", opts: {}, isCron: false },
|
|
@@ -418,18 +423,18 @@ function buildJobName(namespace, name) {
|
|
|
418
423
|
* // ]
|
|
419
424
|
* ```
|
|
420
425
|
*/
|
|
421
|
-
function
|
|
422
|
-
const
|
|
423
|
-
if (!
|
|
426
|
+
function collectJobMetadata(target) {
|
|
427
|
+
const jobStore = _tsed_core.Store.from(target).get(MONQUE);
|
|
428
|
+
if (!jobStore) return [];
|
|
424
429
|
const results = [];
|
|
425
|
-
const namespace =
|
|
426
|
-
for (const
|
|
427
|
-
fullName: buildJobName(namespace,
|
|
428
|
-
method:
|
|
429
|
-
opts:
|
|
430
|
+
const namespace = jobStore.namespace;
|
|
431
|
+
for (const job of jobStore.jobs) results.push({
|
|
432
|
+
fullName: buildJobName(namespace, job.name),
|
|
433
|
+
method: job.method,
|
|
434
|
+
opts: job.opts,
|
|
430
435
|
isCron: false
|
|
431
436
|
});
|
|
432
|
-
for (const cron of
|
|
437
|
+
for (const cron of jobStore.cronJobs) results.push({
|
|
433
438
|
fullName: buildJobName(namespace, cron.name),
|
|
434
439
|
method: cron.method,
|
|
435
440
|
opts: cron.opts,
|
|
@@ -440,29 +445,29 @@ function collectWorkerMetadata(target) {
|
|
|
440
445
|
}
|
|
441
446
|
|
|
442
447
|
//#endregion
|
|
443
|
-
//#region src/utils/get-
|
|
448
|
+
//#region src/utils/get-job-token.ts
|
|
444
449
|
/**
|
|
445
|
-
* Generate a unique token for a
|
|
450
|
+
* Generate a unique token for a job controller.
|
|
446
451
|
*
|
|
447
|
-
* Used internally by Ts.ED DI to identify
|
|
452
|
+
* Used internally by Ts.ED DI to identify job controller providers.
|
|
448
453
|
* The token is based on the class name for debugging purposes.
|
|
449
454
|
*
|
|
450
455
|
* @param target - The class constructor
|
|
451
|
-
* @returns A Symbol token unique to this
|
|
456
|
+
* @returns A Symbol token unique to this job controller
|
|
452
457
|
*
|
|
453
458
|
* @example
|
|
454
459
|
* ```typescript
|
|
455
|
-
* @
|
|
456
|
-
* class
|
|
460
|
+
* @JobController("email")
|
|
461
|
+
* class EmailJobs {}
|
|
457
462
|
*
|
|
458
|
-
* const token =
|
|
459
|
-
* // Symbol("monque:
|
|
463
|
+
* const token = getJobToken(EmailJobs);
|
|
464
|
+
* // Symbol("monque:job:EmailJobs")
|
|
460
465
|
* ```
|
|
461
466
|
*/
|
|
462
|
-
function
|
|
467
|
+
function getJobToken(target) {
|
|
463
468
|
const name = target.name?.trim();
|
|
464
|
-
if (!name) throw new
|
|
465
|
-
return Symbol.for(`monque:
|
|
469
|
+
if (!name) throw new _monque_core.MonqueError("Job class must have a non-empty name");
|
|
470
|
+
return Symbol.for(`monque:job:${name}`);
|
|
466
471
|
}
|
|
467
472
|
|
|
468
473
|
//#endregion
|
|
@@ -491,6 +496,11 @@ function isMongooseConnection(value) {
|
|
|
491
496
|
//#endregion
|
|
492
497
|
//#region src/utils/resolve-database.ts
|
|
493
498
|
/**
|
|
499
|
+
* @monque/tsed - Database Resolution Utility
|
|
500
|
+
*
|
|
501
|
+
* Multi-strategy database resolution for flexible MongoDB connection handling.
|
|
502
|
+
*/
|
|
503
|
+
/**
|
|
494
504
|
* Resolve the MongoDB database instance from the configuration.
|
|
495
505
|
*
|
|
496
506
|
* Supports three resolution strategies:
|
|
@@ -527,20 +537,20 @@ async function resolveDatabase(config, injectorFn) {
|
|
|
527
537
|
if (config.db) return config.db;
|
|
528
538
|
if (config.dbFactory) return config.dbFactory();
|
|
529
539
|
if (config.dbToken) {
|
|
530
|
-
if (!injectorFn) throw new
|
|
540
|
+
if (!injectorFn) throw new _monque_core.ConnectionError("MonqueTsedConfig.dbToken requires an injector function to resolve the database");
|
|
531
541
|
const resolved = injectorFn(config.dbToken);
|
|
532
|
-
if (!resolved) throw new
|
|
542
|
+
if (!resolved) throw new _monque_core.ConnectionError(`Could not resolve database from token: ${String(config.dbToken)}. Make sure the provider is registered in the DI container.`);
|
|
533
543
|
if (isMongooseService(resolved)) {
|
|
534
544
|
const connectionId = config.mongooseConnectionId || "default";
|
|
535
545
|
const connection = resolved.get(connectionId);
|
|
536
|
-
if (!connection) throw new
|
|
546
|
+
if (!connection) throw new _monque_core.ConnectionError(`MongooseService resolved from token "${String(config.dbToken)}" returned no connection for ID "${connectionId}". Ensure the connection ID is correct and the connection is established.`);
|
|
537
547
|
if ("db" in connection && connection.db) return connection.db;
|
|
538
548
|
}
|
|
539
549
|
if (isMongooseConnection(resolved)) return resolved.db;
|
|
540
|
-
if (typeof resolved !== "object" || resolved === null || !("collection" in resolved)) throw new
|
|
550
|
+
if (typeof resolved !== "object" || resolved === null || !("collection" in resolved)) throw new _monque_core.ConnectionError(`Resolved value from token "${String(config.dbToken)}" does not appear to be a valid MongoDB Db instance.`);
|
|
541
551
|
return resolved;
|
|
542
552
|
}
|
|
543
|
-
throw new
|
|
553
|
+
throw new _monque_core.ConnectionError("MonqueTsedConfig requires 'db', 'dbFactory', or 'dbToken' to be set");
|
|
544
554
|
}
|
|
545
555
|
|
|
546
556
|
//#endregion
|
|
@@ -563,7 +573,7 @@ function __decorateParam(paramIndex, decorator) {
|
|
|
563
573
|
* MonqueModule - Main Integration Module
|
|
564
574
|
*
|
|
565
575
|
* Orchestrates the integration between Monque and Ts.ED.
|
|
566
|
-
* Handles lifecycle hooks, configuration resolution, and
|
|
576
|
+
* Handles lifecycle hooks, configuration resolution, and job registration.
|
|
567
577
|
*/
|
|
568
578
|
var _ref, _ref2, _ref3, _ref4;
|
|
569
579
|
let MonqueModule = class MonqueModule {
|
|
@@ -592,9 +602,12 @@ let MonqueModule = class MonqueModule {
|
|
|
592
602
|
this.monqueService._setMonque(this.monque);
|
|
593
603
|
this.logger.info("Monque: Connecting to MongoDB...");
|
|
594
604
|
await this.monque.initialize();
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
605
|
+
if (config.disableJobProcessing) this.logger.info("Monque: Job processing is disabled for this instance");
|
|
606
|
+
else {
|
|
607
|
+
await this.registerJobs();
|
|
608
|
+
await this.monque.start();
|
|
609
|
+
this.logger.info("Monque: Started successfully");
|
|
610
|
+
}
|
|
598
611
|
} catch (error) {
|
|
599
612
|
this.logger.error({
|
|
600
613
|
event: "MONQUE_INIT_ERROR",
|
|
@@ -612,25 +625,25 @@ let MonqueModule = class MonqueModule {
|
|
|
612
625
|
}
|
|
613
626
|
}
|
|
614
627
|
/**
|
|
615
|
-
* Discover and register all
|
|
628
|
+
* Discover and register all jobs from @JobController providers
|
|
616
629
|
*/
|
|
617
|
-
async
|
|
618
|
-
if (!this.monque) throw new
|
|
630
|
+
async registerJobs() {
|
|
631
|
+
if (!this.monque) throw new _monque_core.MonqueError("Monque instance not initialized");
|
|
619
632
|
const monque = this.monque;
|
|
620
|
-
const
|
|
633
|
+
const jobControllers = this.injector.getProviders(ProviderTypes.JOB_CONTROLLER);
|
|
621
634
|
const registeredJobs = /* @__PURE__ */ new Set();
|
|
622
|
-
this.logger.info(`Monque: Found ${
|
|
623
|
-
for (const provider of
|
|
635
|
+
this.logger.info(`Monque: Found ${jobControllers.length} job controllers`);
|
|
636
|
+
for (const provider of jobControllers) {
|
|
624
637
|
const useClass = provider.useClass;
|
|
625
|
-
const
|
|
638
|
+
const jobs = collectJobMetadata(useClass);
|
|
626
639
|
const instance = this.injector.get(provider.token);
|
|
627
640
|
if (!instance && provider.scope !== _tsed_di.ProviderScope.REQUEST) {
|
|
628
641
|
this.logger.warn(`Monque: Could not resolve instance for controller ${provider.name}. Skipping.`);
|
|
629
642
|
continue;
|
|
630
643
|
}
|
|
631
|
-
for (const
|
|
632
|
-
const { fullName, method, opts, isCron, cronPattern } =
|
|
633
|
-
if (registeredJobs.has(fullName)) throw new
|
|
644
|
+
for (const job of jobs) {
|
|
645
|
+
const { fullName, method, opts, isCron, cronPattern } = job;
|
|
646
|
+
if (registeredJobs.has(fullName)) throw new _monque_core.WorkerRegistrationError(`Monque: Duplicate job registration detected. Job "${fullName}" is already registered.`, fullName);
|
|
634
647
|
registeredJobs.add(fullName);
|
|
635
648
|
const handler = async (job) => {
|
|
636
649
|
const $ctx = new _tsed_di.DIContext({
|
|
@@ -664,7 +677,7 @@ let MonqueModule = class MonqueModule {
|
|
|
664
677
|
monque.register(fullName, handler, opts);
|
|
665
678
|
await monque.schedule(cronPattern, fullName, {}, opts);
|
|
666
679
|
} else {
|
|
667
|
-
this.logger.debug(`Monque: Registering
|
|
680
|
+
this.logger.debug(`Monque: Registering job "${fullName}"`);
|
|
668
681
|
monque.register(fullName, handler, opts);
|
|
669
682
|
}
|
|
670
683
|
}
|
|
@@ -688,6 +701,8 @@ MonqueModule = __decorate([
|
|
|
688
701
|
|
|
689
702
|
//#endregion
|
|
690
703
|
exports.Cron = Cron;
|
|
704
|
+
exports.Job = Job;
|
|
705
|
+
exports.JobController = JobController;
|
|
691
706
|
exports.MONQUE = MONQUE;
|
|
692
707
|
Object.defineProperty(exports, 'MonqueModule', {
|
|
693
708
|
enumerable: true,
|
|
@@ -702,11 +717,9 @@ Object.defineProperty(exports, 'MonqueService', {
|
|
|
702
717
|
}
|
|
703
718
|
});
|
|
704
719
|
exports.ProviderTypes = ProviderTypes;
|
|
705
|
-
exports.Worker = Worker;
|
|
706
|
-
exports.WorkerController = WorkerController;
|
|
707
720
|
exports.buildJobName = buildJobName;
|
|
708
|
-
exports.
|
|
709
|
-
exports.
|
|
721
|
+
exports.collectJobMetadata = collectJobMetadata;
|
|
722
|
+
exports.getJobToken = getJobToken;
|
|
710
723
|
exports.resolveDatabase = resolveDatabase;
|
|
711
724
|
exports.validateDatabaseConfig = validateDatabaseConfig;
|
|
712
725
|
//# sourceMappingURL=index.cjs.map
|