nmtjs 0.16.0-beta.9 → 0.16.1
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/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/entrypoints/worker.js +9 -9
- package/dist/entrypoints/worker.js.map +1 -1
- package/dist/index.d.ts +58 -15
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/runtime/application/index.d.ts +1 -5
- package/dist/runtime/application/index.js +1 -5
- package/dist/runtime/application/index.js.map +1 -1
- package/dist/runtime/enums.d.ts +1 -12
- package/dist/runtime/enums.js +1 -14
- package/dist/runtime/enums.js.map +1 -1
- package/dist/runtime/hooks.d.ts +1 -4
- package/dist/runtime/hooks.js +1 -3
- package/dist/runtime/hooks.js.map +1 -1
- package/dist/runtime/index.d.ts +1 -3
- package/dist/runtime/index.js +1 -3
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/injectables.d.ts +48 -7
- package/dist/runtime/injectables.js +19 -3
- package/dist/runtime/injectables.js.map +1 -1
- package/dist/runtime/jobs/job.d.ts +1 -2
- package/dist/runtime/jobs/job.js.map +1 -1
- package/dist/runtime/jobs/router.d.ts +2 -5
- package/dist/runtime/jobs/router.js +2 -3
- package/dist/runtime/jobs/router.js.map +1 -1
- package/dist/runtime/jobs/runner.d.ts +1 -1
- package/dist/runtime/jobs/runner.js +1 -1
- package/dist/runtime/jobs/runner.js.map +1 -1
- package/dist/runtime/jobs/types.d.ts +1 -1
- package/dist/runtime/metrics/metric.d.ts +2 -2
- package/dist/runtime/metrics/metric.js +1 -1
- package/dist/runtime/metrics/metric.js.map +1 -1
- package/dist/runtime/metrics/registry.d.ts +3 -3
- package/dist/runtime/metrics/registry.js +1 -1
- package/dist/runtime/metrics/registry.js.map +1 -1
- package/dist/runtime/metrics/server.js +1 -1
- package/dist/runtime/metrics/server.js.map +1 -1
- package/dist/runtime/plugin.d.ts +2 -8
- package/dist/runtime/plugin.js +1 -3
- package/dist/runtime/plugin.js.map +1 -1
- package/dist/runtime/runtime.d.ts +2 -2
- package/dist/runtime/runtime.js +1 -2
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/server/applications.js +3 -0
- package/dist/runtime/server/applications.js.map +1 -1
- package/dist/runtime/server/config.d.ts +15 -12
- package/dist/runtime/server/config.js.map +1 -1
- package/dist/runtime/server/jobs.d.ts +6 -7
- package/dist/runtime/server/jobs.js +44 -30
- package/dist/runtime/server/jobs.js.map +1 -1
- package/dist/runtime/subscription/manager.d.ts +3 -3
- package/dist/runtime/subscription/manager.js +8 -8
- package/dist/runtime/subscription/manager.js.map +1 -1
- package/dist/runtime/subscription/redis.d.ts +1 -1
- package/dist/runtime/subscription/redis.js +16 -17
- package/dist/runtime/subscription/redis.js.map +1 -1
- package/dist/runtime/types.d.ts +3 -11
- package/dist/runtime/workers/application.d.ts +15 -33
- package/dist/runtime/workers/application.js +46 -139
- package/dist/runtime/workers/application.js.map +1 -1
- package/dist/runtime/workers/base.d.ts +0 -2
- package/dist/runtime/workers/base.js +3 -8
- package/dist/runtime/workers/base.js.map +1 -1
- package/dist/runtime/workers/job.js +2 -1
- package/dist/runtime/workers/job.js.map +1 -1
- package/dist/vite/server.js +1 -1
- package/dist/vite/server.js.map +1 -1
- package/package.json +19 -14
- package/src/cli.ts +2 -3
- package/src/entrypoints/worker.ts +11 -9
- package/src/index.ts +12 -5
- package/src/runtime/application/index.ts +1 -5
- package/src/runtime/enums.ts +2 -14
- package/src/runtime/hooks.ts +1 -5
- package/src/runtime/index.ts +2 -3
- package/src/runtime/injectables.ts +35 -6
- package/src/runtime/jobs/job.ts +1 -2
- package/src/runtime/jobs/router.ts +12 -15
- package/src/runtime/jobs/runner.ts +2 -2
- package/src/runtime/jobs/types.ts +1 -1
- package/src/runtime/metrics/metric.ts +2 -2
- package/src/runtime/metrics/registry.ts +5 -1
- package/src/runtime/metrics/server.ts +1 -1
- package/src/runtime/plugin.ts +2 -13
- package/src/runtime/runtime.ts +2 -4
- package/src/runtime/server/applications.ts +6 -0
- package/src/runtime/server/config.ts +27 -21
- package/src/runtime/server/jobs.ts +58 -34
- package/src/runtime/subscription/manager.ts +11 -14
- package/src/runtime/subscription/redis.ts +25 -23
- package/src/runtime/types.ts +3 -12
- package/src/runtime/workers/application.ts +76 -160
- package/src/runtime/workers/base.ts +9 -15
- package/src/runtime/workers/job.ts +3 -6
- package/src/vite/server.ts +1 -1
- package/dist/runtime/application/api/api.d.ts +0 -55
- package/dist/runtime/application/api/api.js +0 -252
- package/dist/runtime/application/api/api.js.map +0 -1
- package/dist/runtime/application/api/config.d.ts +0 -14
- package/dist/runtime/application/api/config.js +0 -6
- package/dist/runtime/application/api/config.js.map +0 -1
- package/dist/runtime/application/api/constants.d.ts +0 -14
- package/dist/runtime/application/api/constants.js +0 -8
- package/dist/runtime/application/api/constants.js.map +0 -1
- package/dist/runtime/application/api/filters.d.ts +0 -14
- package/dist/runtime/application/api/filters.js +0 -11
- package/dist/runtime/application/api/filters.js.map +0 -1
- package/dist/runtime/application/api/guards.d.ts +0 -15
- package/dist/runtime/application/api/guards.js +0 -8
- package/dist/runtime/application/api/guards.js.map +0 -1
- package/dist/runtime/application/api/index.d.ts +0 -23
- package/dist/runtime/application/api/index.js +0 -17
- package/dist/runtime/application/api/index.js.map +0 -1
- package/dist/runtime/application/api/logging.d.ts +0 -14
- package/dist/runtime/application/api/logging.js +0 -77
- package/dist/runtime/application/api/logging.js.map +0 -1
- package/dist/runtime/application/api/meta.d.ts +0 -21
- package/dist/runtime/application/api/meta.js +0 -2
- package/dist/runtime/application/api/meta.js.map +0 -1
- package/dist/runtime/application/api/middlewares.d.ts +0 -14
- package/dist/runtime/application/api/middlewares.js +0 -12
- package/dist/runtime/application/api/middlewares.js.map +0 -1
- package/dist/runtime/application/api/procedure.d.ts +0 -71
- package/dist/runtime/application/api/procedure.js +0 -41
- package/dist/runtime/application/api/procedure.js.map +0 -1
- package/dist/runtime/application/api/router.d.ts +0 -93
- package/dist/runtime/application/api/router.js +0 -55
- package/dist/runtime/application/api/router.js.map +0 -1
- package/dist/runtime/application/api/types.d.ts +0 -38
- package/dist/runtime/application/api/types.js +0 -2
- package/dist/runtime/application/api/types.js.map +0 -1
- package/dist/runtime/application/config.d.ts +0 -28
- package/dist/runtime/application/config.js +0 -25
- package/dist/runtime/application/config.js.map +0 -1
- package/dist/runtime/application/constants.d.ts +0 -2
- package/dist/runtime/application/constants.js +0 -2
- package/dist/runtime/application/constants.js.map +0 -1
- package/dist/runtime/application/hook.d.ts +0 -19
- package/dist/runtime/application/hook.js +0 -11
- package/dist/runtime/application/hook.js.map +0 -1
- package/dist/runtime/application/hooks.d.ts +0 -3
- package/dist/runtime/application/hooks.js +0 -4
- package/dist/runtime/application/hooks.js.map +0 -1
- package/src/runtime/application/api/api.ts +0 -406
- package/src/runtime/application/api/config.ts +0 -18
- package/src/runtime/application/api/constants.ts +0 -22
- package/src/runtime/application/api/filters.ts +0 -39
- package/src/runtime/application/api/guards.ts +0 -33
- package/src/runtime/application/api/index.ts +0 -69
- package/src/runtime/application/api/logging.ts +0 -110
- package/src/runtime/application/api/meta.ts +0 -37
- package/src/runtime/application/api/middlewares.ts +0 -37
- package/src/runtime/application/api/procedure.ts +0 -224
- package/src/runtime/application/api/router.ts +0 -247
- package/src/runtime/application/api/types.ts +0 -138
- package/src/runtime/application/config.ts +0 -82
- package/src/runtime/application/constants.ts +0 -4
- package/src/runtime/application/hook.ts +0 -51
- package/src/runtime/application/hooks.ts +0 -3
|
@@ -14,10 +14,12 @@ import type {
|
|
|
14
14
|
WorkerPoolConfig,
|
|
15
15
|
WorkerPoolFactory,
|
|
16
16
|
} from './worker-pool.ts'
|
|
17
|
-
import {
|
|
17
|
+
import { WorkerType } from '../enums.ts'
|
|
18
18
|
import { getJobQueueName } from '../jobs/manager.ts'
|
|
19
19
|
import { JobRunnersPool } from './worker-pool.ts'
|
|
20
20
|
|
|
21
|
+
type JobsPoolConfig = Exclude<ServerConfig['jobs'], undefined>['pools']
|
|
22
|
+
|
|
21
23
|
function enrichBullMqErrorStack(error: unknown): Error {
|
|
22
24
|
const normalized =
|
|
23
25
|
error instanceof Error
|
|
@@ -31,6 +33,38 @@ function enrichBullMqErrorStack(error: unknown): Error {
|
|
|
31
33
|
return normalized
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
function getJobsByPool(jobs: Iterable<AnyJob>): Map<string, AnyJob[]> {
|
|
37
|
+
const jobsByPool = new Map<string, AnyJob[]>()
|
|
38
|
+
|
|
39
|
+
for (const job of jobs) {
|
|
40
|
+
const poolJobs = jobsByPool.get(job.options.pool)
|
|
41
|
+
if (poolJobs) {
|
|
42
|
+
poolJobs.push(job)
|
|
43
|
+
} else {
|
|
44
|
+
jobsByPool.set(job.options.pool, [job])
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return jobsByPool
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function assertActiveJobPoolsConfigured(
|
|
52
|
+
jobsByPool: Map<string, AnyJob[]>,
|
|
53
|
+
pools: JobsPoolConfig,
|
|
54
|
+
) {
|
|
55
|
+
const missingPoolMessages = [...jobsByPool]
|
|
56
|
+
.filter(([poolName]) => !pools[poolName])
|
|
57
|
+
.flatMap(([poolName, jobs]) =>
|
|
58
|
+
jobs.map((job) => `${job.name} -> ${poolName}`),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if (missingPoolMessages.length > 0) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Invalid jobs pool configuration: missing pool config for jobs: ${missingPoolMessages.join(', ')}`,
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
34
68
|
/**
|
|
35
69
|
* ApplicationServerJobs manages job worker pools and BullMQ queue workers.
|
|
36
70
|
*
|
|
@@ -38,7 +72,7 @@ function enrichBullMqErrorStack(error: unknown): Error {
|
|
|
38
72
|
* - Uses JobRunnersPool (extends WorkerPool) for worker management
|
|
39
73
|
* - Uses ManagedWorker for restart logic and state tracking
|
|
40
74
|
* - Integrates with ErrorPolicy for restart decisions
|
|
41
|
-
* - Proper health tracking per job pool
|
|
75
|
+
* - Proper health tracking per job pool
|
|
42
76
|
*/
|
|
43
77
|
export class ApplicationServerJobs {
|
|
44
78
|
/**
|
|
@@ -49,10 +83,10 @@ export class ApplicationServerJobs {
|
|
|
49
83
|
jobs: Map<string, AnyJob>
|
|
50
84
|
|
|
51
85
|
/**
|
|
52
|
-
* Shared resource pools by pool
|
|
53
|
-
* All jobs
|
|
86
|
+
* Shared resource pools by configured pool name.
|
|
87
|
+
* All jobs using the same pool name share the same pool for resource management.
|
|
54
88
|
*/
|
|
55
|
-
protected pools = new Map<
|
|
89
|
+
protected pools = new Map<string, JobRunnersPool>()
|
|
56
90
|
|
|
57
91
|
constructor(
|
|
58
92
|
readonly params: {
|
|
@@ -86,16 +120,16 @@ export class ApplicationServerJobs {
|
|
|
86
120
|
return
|
|
87
121
|
}
|
|
88
122
|
|
|
89
|
-
|
|
90
|
-
|
|
123
|
+
const jobsByPool = getJobsByPool(this.jobs.values())
|
|
124
|
+
assertActiveJobPoolsConfigured(jobsByPool, jobsConfig.pools)
|
|
91
125
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
126
|
+
// Step 1: Initialize shared resource pools used by active jobs
|
|
127
|
+
for (const poolName of jobsByPool.keys()) {
|
|
128
|
+
const poolConfig = jobsConfig.pools[poolName]!
|
|
95
129
|
|
|
96
|
-
// Create a JobRunnersPool for this pool
|
|
130
|
+
// Create a JobRunnersPool for this pool
|
|
97
131
|
const config: WorkerPoolConfig = {
|
|
98
|
-
name: `job-pool-${
|
|
132
|
+
name: `job-pool-${poolName}`,
|
|
99
133
|
workerType: WorkerType.Job,
|
|
100
134
|
path: workerConfig.path,
|
|
101
135
|
workerData: { ...workerConfig.workerData },
|
|
@@ -111,15 +145,15 @@ export class ApplicationServerJobs {
|
|
|
111
145
|
|
|
112
146
|
// Add workers to the pool
|
|
113
147
|
for (let i = 0; i < poolConfig.threads; i++) {
|
|
114
|
-
pool.add({ runtime: { type: 'jobs', jobWorkerPool:
|
|
148
|
+
pool.add({ runtime: { type: 'jobs', jobWorkerPool: poolName } }, i)
|
|
115
149
|
}
|
|
116
150
|
|
|
117
151
|
await pool.startAll()
|
|
118
|
-
this.pools.set(
|
|
152
|
+
this.pools.set(poolName, pool)
|
|
119
153
|
|
|
120
154
|
logger.info(
|
|
121
155
|
{
|
|
122
|
-
pool:
|
|
156
|
+
pool: poolName,
|
|
123
157
|
threads: poolConfig.threads,
|
|
124
158
|
jobsPerThread: poolConfig.jobs,
|
|
125
159
|
},
|
|
@@ -129,28 +163,18 @@ export class ApplicationServerJobs {
|
|
|
129
163
|
|
|
130
164
|
// Step 2: Create a dedicated BullMQ Worker for each job
|
|
131
165
|
// Calculate how many jobs use each pool for fair concurrency distribution
|
|
132
|
-
const jobsPerPool = new Map<JobWorkerPool, number>()
|
|
133
|
-
for (const job of this.jobs.values()) {
|
|
134
|
-
const count = jobsPerPool.get(job.options.pool) ?? 0
|
|
135
|
-
jobsPerPool.set(job.options.pool, count + 1)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
166
|
for (const job of this.jobs.values()) {
|
|
139
167
|
const queueName = getJobQueueName(job)
|
|
140
|
-
const
|
|
141
|
-
const pool = this.pools.get(
|
|
168
|
+
const poolName = job.options.pool
|
|
169
|
+
const pool = this.pools.get(poolName)
|
|
142
170
|
|
|
143
171
|
if (!pool) {
|
|
144
|
-
|
|
145
|
-
{ job: job.name, pool: poolType },
|
|
146
|
-
'No pool configured for job, skipping worker creation',
|
|
147
|
-
)
|
|
148
|
-
continue
|
|
172
|
+
throw new Error(`Job "${job.name}" pool "${poolName}" is not started`)
|
|
149
173
|
}
|
|
150
174
|
|
|
151
|
-
const poolConfig = jobsConfig.pools[
|
|
175
|
+
const poolConfig = jobsConfig.pools[poolName]!
|
|
152
176
|
const poolCapacity = poolConfig.threads * poolConfig.jobs
|
|
153
|
-
const jobCountInPool =
|
|
177
|
+
const jobCountInPool = jobsByPool.get(poolName)?.length ?? 1
|
|
154
178
|
// Use job-specific concurrency if provided, otherwise distribute pool capacity evenly
|
|
155
179
|
const defaultConcurrency = Math.max(
|
|
156
180
|
1,
|
|
@@ -192,7 +216,7 @@ export class ApplicationServerJobs {
|
|
|
192
216
|
|
|
193
217
|
this.queueWorkers.add(queueWorker)
|
|
194
218
|
logger.info(
|
|
195
|
-
{ job: job.name, queue: queueName, pool:
|
|
219
|
+
{ job: job.name, queue: queueName, pool: poolName, concurrency },
|
|
196
220
|
'Job queue worker started',
|
|
197
221
|
)
|
|
198
222
|
}
|
|
@@ -234,9 +258,9 @@ export class ApplicationServerJobs {
|
|
|
234
258
|
}
|
|
235
259
|
|
|
236
260
|
/**
|
|
237
|
-
* Get a job pool by
|
|
261
|
+
* Get a job pool by name.
|
|
238
262
|
*/
|
|
239
|
-
getPool(
|
|
240
|
-
return this.pools.get(
|
|
263
|
+
getPool(poolName: string): JobRunnersPool | undefined {
|
|
264
|
+
return this.pools.get(poolName)
|
|
241
265
|
}
|
|
242
266
|
}
|
|
@@ -7,12 +7,10 @@ import type {
|
|
|
7
7
|
TAnyEventContract,
|
|
8
8
|
TAnySubscriptionContract,
|
|
9
9
|
} from '@nmtjs/contract'
|
|
10
|
-
import type {
|
|
10
|
+
import type { Logger } from '@nmtjs/core'
|
|
11
11
|
import type { t } from '@nmtjs/type'
|
|
12
12
|
import { isAbortError } from '@nmtjs/common'
|
|
13
13
|
|
|
14
|
-
import { subscriptionAdapter } from '../injectables.ts'
|
|
15
|
-
|
|
16
14
|
export type SubscriptionAdapterEvent = { channel: string; payload: any }
|
|
17
15
|
|
|
18
16
|
export interface SubscriptionAdapterType {
|
|
@@ -74,7 +72,7 @@ export type PublishFn = <
|
|
|
74
72
|
|
|
75
73
|
export type SubscriptionManagerOptions = {
|
|
76
74
|
logger: Logger
|
|
77
|
-
|
|
75
|
+
adapter: SubscriptionAdapterType
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
export class SubscriptionManager {
|
|
@@ -85,13 +83,7 @@ export class SubscriptionManager {
|
|
|
85
83
|
this.logger = options.logger.child({ component: SubscriptionManager.name })
|
|
86
84
|
}
|
|
87
85
|
|
|
88
|
-
protected get adapter() {
|
|
89
|
-
return this.options.container.resolve(subscriptionAdapter)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
86
|
subscribe: SubscribeFn = async (subscription, events, options, signal) => {
|
|
93
|
-
const adapter = await this.adapter
|
|
94
|
-
|
|
95
87
|
const eventKeys =
|
|
96
88
|
Object.keys(events).length === 0
|
|
97
89
|
? Object.keys(subscription.events)
|
|
@@ -118,7 +110,7 @@ export class SubscriptionManager {
|
|
|
118
110
|
'Reusing pubsub channel stream',
|
|
119
111
|
)
|
|
120
112
|
} else {
|
|
121
|
-
const iterable = adapter.subscribe(channel, signal)
|
|
113
|
+
const iterable = this.options.adapter.subscribe(channel, signal)
|
|
122
114
|
const stream = this.createEventStream(iterable)
|
|
123
115
|
stream.on('close', () => {
|
|
124
116
|
this.subscriptions.delete(channel)
|
|
@@ -173,15 +165,13 @@ export class SubscriptionManager {
|
|
|
173
165
|
}
|
|
174
166
|
|
|
175
167
|
publish: PublishFn = async (event, options, data) => {
|
|
176
|
-
const adapter = await this.adapter
|
|
177
|
-
|
|
178
168
|
const channel = getChannelName(event, options)
|
|
179
169
|
|
|
180
170
|
this.logger.trace({ channel, event: event.name }, 'Publishing pubsub event')
|
|
181
171
|
|
|
182
172
|
try {
|
|
183
173
|
const payload = event.payload.encode(data)
|
|
184
|
-
const published = await adapter.publish(channel, payload)
|
|
174
|
+
const published = await this.options.adapter.publish(channel, payload)
|
|
185
175
|
|
|
186
176
|
if (published) {
|
|
187
177
|
this.logger.trace(
|
|
@@ -205,6 +195,13 @@ export class SubscriptionManager {
|
|
|
205
195
|
}
|
|
206
196
|
}
|
|
207
197
|
|
|
198
|
+
async dispose(): Promise<void> {
|
|
199
|
+
for (const { stream } of this.subscriptions.values()) {
|
|
200
|
+
stream.destroy()
|
|
201
|
+
}
|
|
202
|
+
this.subscriptions.clear()
|
|
203
|
+
}
|
|
204
|
+
|
|
208
205
|
private createEventStream(
|
|
209
206
|
iterable: AsyncGenerator<SubscriptionAdapterEvent>,
|
|
210
207
|
): Readable {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import EventEmitter, { on } from 'node:events'
|
|
2
2
|
|
|
3
|
+
import type { RuntimePlugin } from '@nmtjs/application'
|
|
3
4
|
import type { Logger } from '@nmtjs/core'
|
|
4
5
|
import { isAbortError } from '@nmtjs/common'
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
CoreInjectables,
|
|
8
|
+
createFactoryInjectable,
|
|
9
|
+
provision,
|
|
10
|
+
} from '@nmtjs/core'
|
|
6
11
|
|
|
7
|
-
import type { RuntimePlugin } from '../plugin.ts'
|
|
8
12
|
import type { Store } from '../types.ts'
|
|
9
13
|
import type {
|
|
10
14
|
SubscriptionAdapterEvent,
|
|
@@ -130,28 +134,26 @@ export class RedisSubscriptionAdapter implements SubscriptionAdapterType {
|
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
export const RedisSubscriptionAdapterPlugin = (): RuntimePlugin => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
await adapter.initialize()
|
|
147
|
-
return { adapter, connection }
|
|
148
|
-
},
|
|
149
|
-
pick: ({ adapter }) => adapter,
|
|
150
|
-
dispose: ({ connection }) => connection.quit(),
|
|
151
|
-
}),
|
|
152
|
-
)
|
|
153
|
-
ctx.container.provide(subscriptionAdapter, adapter)
|
|
137
|
+
const adapterFactory = createFactoryInjectable(
|
|
138
|
+
{
|
|
139
|
+
dependencies: { config: storeConfig, logger: CoreInjectables.logger },
|
|
140
|
+
factory: async ({ config, logger }) => {
|
|
141
|
+
const connection = await createStoreClient(config)
|
|
142
|
+
const adapter = new RedisSubscriptionAdapter(connection, logger)
|
|
143
|
+
await adapter.initialize()
|
|
144
|
+
return { adapter, connection }
|
|
145
|
+
},
|
|
146
|
+
pick: ({ adapter }) => adapter,
|
|
147
|
+
dispose: async ({ adapter, connection }) => {
|
|
148
|
+
await adapter.dispose()
|
|
149
|
+
await connection.quit()
|
|
154
150
|
},
|
|
155
151
|
},
|
|
152
|
+
'RedisSubscriptionAdapter',
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
name: 'redis-subscription-adapter',
|
|
157
|
+
injections: [provision(subscriptionAdapter, adapterFactory)],
|
|
156
158
|
}
|
|
157
159
|
}
|
package/src/runtime/types.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ApplicationHostDefinition } from '@nmtjs/application'
|
|
2
2
|
import type { ProxyableTransportType } from '@nmtjs/gateway'
|
|
3
3
|
import type { Redis, RedisOptions } from 'ioredis'
|
|
4
4
|
import type { Redis as Valkey, RedisOptions as ValkeyOptions } from 'iovalkey'
|
|
5
5
|
|
|
6
|
-
import type {
|
|
7
|
-
import type { LifecycleHook, StoreType } from './enums.ts'
|
|
8
|
-
import type { BaseRuntime } from './runtime.ts'
|
|
6
|
+
import type { StoreType } from './enums.ts'
|
|
9
7
|
|
|
10
8
|
export type WorkerThreadErrorOrigin = 'bootstrap' | 'start' | 'runtime'
|
|
11
9
|
|
|
@@ -66,15 +64,8 @@ export type JobTaskResultTypes = {
|
|
|
66
64
|
queue_job_not_found: {}
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
export interface LifecycleHookTypes extends HookTypes {
|
|
70
|
-
[LifecycleHook.BeforeInitialize]: (runtime: BaseRuntime) => any
|
|
71
|
-
[LifecycleHook.AfterInitialize]: (runtime: BaseRuntime) => any
|
|
72
|
-
[LifecycleHook.BeforeDispose]: (runtime: BaseRuntime) => any
|
|
73
|
-
[LifecycleHook.AfterDispose]: (runtime: BaseRuntime) => any
|
|
74
|
-
}
|
|
75
|
-
|
|
76
67
|
export type ApplicationDefinitionType =
|
|
77
|
-
| { type: 'neemata'; definition:
|
|
68
|
+
| { type: 'neemata'; definition: ApplicationHostDefinition }
|
|
78
69
|
| { type: 'custom'; definition: any }
|
|
79
70
|
|
|
80
71
|
export interface Applications
|
|
@@ -1,217 +1,133 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ApplicationHost,
|
|
3
|
+
ApplicationHostDefinition,
|
|
4
|
+
ApplicationHostOptions,
|
|
5
|
+
ApplicationResolvedProcedure,
|
|
6
|
+
ApplicationTransport,
|
|
7
|
+
NeemataApplication,
|
|
8
|
+
TransportOptionsOf,
|
|
9
|
+
} from '@nmtjs/application'
|
|
10
|
+
import type { Gateway, GatewayOptions } from '@nmtjs/gateway'
|
|
11
|
+
import { createApplicationHost, LifecycleHook } from '@nmtjs/application'
|
|
4
12
|
import { JsonFormat } from '@nmtjs/json-format/server'
|
|
5
13
|
import { MsgpackFormat } from '@nmtjs/msgpack-format/server'
|
|
6
14
|
import { ProtocolFormats } from '@nmtjs/protocol/server'
|
|
7
15
|
|
|
8
|
-
import type {
|
|
9
|
-
import
|
|
10
|
-
AnyFilter,
|
|
11
|
-
AnyGuard,
|
|
12
|
-
AnyMiddleware,
|
|
13
|
-
AnyProcedure,
|
|
14
|
-
AnyRouter,
|
|
15
|
-
kDefaultProcedure as kDefaultProcedureKey,
|
|
16
|
-
} from '../application/index.ts'
|
|
17
|
-
import type { ServerConfig } from '../server/config.ts'
|
|
18
|
-
import { ApplicationApi } from '../application/api/api.ts'
|
|
19
|
-
import { ApplicationHooks } from '../application/hooks.ts'
|
|
20
|
-
import {
|
|
21
|
-
isProcedure,
|
|
22
|
-
isRootRouter,
|
|
23
|
-
isRouter,
|
|
24
|
-
kDefaultProcedure,
|
|
25
|
-
kRootRouter,
|
|
26
|
-
} from '../application/index.ts'
|
|
27
|
-
import { LifecycleHook, WorkerType } from '../enums.ts'
|
|
16
|
+
import type { ServerApplicationConfig, ServerConfig } from '../server/config.ts'
|
|
17
|
+
import { WorkerType } from '../enums.ts'
|
|
28
18
|
import { BaseWorkerRuntime } from './base.ts'
|
|
29
19
|
|
|
30
20
|
export interface ApplicationWorkerRuntimeOptions {
|
|
31
21
|
name: string
|
|
32
22
|
path: string
|
|
33
|
-
transports:
|
|
23
|
+
transports: ServerApplicationConfig['threads'][number]
|
|
34
24
|
}
|
|
35
25
|
|
|
36
26
|
export class ApplicationWorkerRuntime extends BaseWorkerRuntime {
|
|
37
|
-
|
|
38
|
-
applicationHooks!: ApplicationHooks
|
|
39
|
-
gateway!: Gateway
|
|
40
|
-
transports!: GatewayOptions['transports']
|
|
41
|
-
|
|
42
|
-
routers = new Map<string | kRootRouter, AnyRouter>()
|
|
43
|
-
procedures = new Map<
|
|
44
|
-
string | kDefaultProcedureKey,
|
|
45
|
-
{ procedure: AnyProcedure; path: AnyRouter[] }
|
|
46
|
-
>()
|
|
47
|
-
filters = new Set<AnyFilter>()
|
|
48
|
-
middlewares = new Set<AnyMiddleware>()
|
|
49
|
-
guards = new Set<AnyGuard>()
|
|
27
|
+
host!: ApplicationHost
|
|
50
28
|
|
|
51
29
|
constructor(
|
|
52
30
|
readonly config: ServerConfig,
|
|
53
31
|
readonly runtimeOptions: ApplicationWorkerRuntimeOptions,
|
|
54
|
-
protected
|
|
32
|
+
protected hostDefinition: ApplicationHostDefinition,
|
|
55
33
|
) {
|
|
56
34
|
super(
|
|
57
35
|
config,
|
|
58
36
|
{
|
|
59
37
|
logger: config.logger,
|
|
60
38
|
name: `Worker ${runtimeOptions.name}`,
|
|
61
|
-
plugins:
|
|
39
|
+
plugins: [],
|
|
62
40
|
},
|
|
63
41
|
WorkerType.Application,
|
|
64
42
|
)
|
|
43
|
+
}
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
get application(): NeemataApplication {
|
|
46
|
+
return this.host.application
|
|
47
|
+
}
|
|
67
48
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
container: this.container,
|
|
71
|
-
logger: this.logger,
|
|
72
|
-
meta: this.appConfig.meta,
|
|
73
|
-
filters: this.filters,
|
|
74
|
-
middlewares: this.middlewares,
|
|
75
|
-
guards: this.guards,
|
|
76
|
-
procedures: this.procedures,
|
|
77
|
-
})
|
|
49
|
+
get api() {
|
|
50
|
+
return this.application.api
|
|
78
51
|
}
|
|
79
52
|
|
|
80
|
-
|
|
81
|
-
|
|
53
|
+
get applicationHooks() {
|
|
54
|
+
return this.application.applicationHooks
|
|
55
|
+
}
|
|
82
56
|
|
|
83
|
-
|
|
57
|
+
get gateway(): Gateway<ApplicationResolvedProcedure> {
|
|
58
|
+
return this.host.gateway
|
|
59
|
+
}
|
|
84
60
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.transports[key] = { transport: await factory(options), proxyable }
|
|
89
|
-
}
|
|
61
|
+
get transports(): GatewayOptions<ApplicationResolvedProcedure>['transports'] {
|
|
62
|
+
return this.host.transports
|
|
63
|
+
}
|
|
90
64
|
|
|
91
|
-
|
|
92
|
-
|
|
65
|
+
async start() {
|
|
66
|
+
await this.initialize()
|
|
67
|
+
this.host = createApplicationHost(this.hostDefinition.application, {
|
|
68
|
+
name: this.runtimeOptions.name,
|
|
93
69
|
logger: this.logger,
|
|
94
70
|
container: this.container,
|
|
95
|
-
hooks: this.lifecycleHooks,
|
|
96
71
|
formats: new ProtocolFormats([new JsonFormat(), new MsgpackFormat()]),
|
|
97
|
-
|
|
98
|
-
api: this.api,
|
|
99
|
-
identity: this.appConfig.identity,
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
return await this.gateway.start().finally(async () => {
|
|
103
|
-
await this.lifecycleHooks.callHook(LifecycleHook.Start)
|
|
72
|
+
...this.resolveHostOptions(),
|
|
104
73
|
})
|
|
74
|
+
return this.host.start()
|
|
105
75
|
}
|
|
106
76
|
|
|
107
77
|
async stop() {
|
|
108
|
-
await this.
|
|
78
|
+
await this.host.stop()
|
|
109
79
|
await this.dispose()
|
|
110
80
|
await this.lifecycleHooks.callHook(LifecycleHook.Stop)
|
|
111
81
|
}
|
|
112
82
|
|
|
113
|
-
async reload(
|
|
114
|
-
|
|
115
|
-
this.
|
|
116
|
-
this.plugins = appConfig.plugins
|
|
117
|
-
await this.initialize()
|
|
118
|
-
this.gateway.options.identity =
|
|
119
|
-
this.appConfig.identity ?? this.gateway.options.identity
|
|
120
|
-
await this.gateway.reload()
|
|
83
|
+
async reload(hostDefinition: ApplicationHostDefinition): Promise<void> {
|
|
84
|
+
this.hostDefinition = hostDefinition
|
|
85
|
+
await this.host.reloadApplication(hostDefinition.application)
|
|
121
86
|
}
|
|
122
87
|
|
|
123
|
-
|
|
124
|
-
this.registerApi()
|
|
125
|
-
this.lifecycleHooks.addHooks(this.appConfig.lifecycleHooks)
|
|
126
|
-
await super.initialize()
|
|
127
|
-
}
|
|
88
|
+
protected *_dependents() {}
|
|
128
89
|
|
|
129
|
-
protected
|
|
130
|
-
|
|
90
|
+
protected resolveHostOptions(): Pick<
|
|
91
|
+
ApplicationHostOptions,
|
|
92
|
+
'transports' | 'gateway' | 'identity'
|
|
93
|
+
> {
|
|
94
|
+
const config = this.config.applications[
|
|
95
|
+
this.runtimeOptions.name
|
|
96
|
+
] as ServerApplicationConfig
|
|
131
97
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
98
|
+
if (!config) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Missing server application config: ${this.runtimeOptions.name}`,
|
|
101
|
+
)
|
|
137
102
|
}
|
|
138
|
-
}
|
|
139
103
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this.routers.clear()
|
|
148
|
-
this.procedures.clear()
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
protected *_dependents(): Generator<Dependant> {
|
|
152
|
-
yield* this.appConfig.filters
|
|
153
|
-
yield* this.appConfig.guards
|
|
154
|
-
yield* this.appConfig.middlewares
|
|
155
|
-
yield* this.appConfig.meta
|
|
156
|
-
yield* this.appConfig.hooks
|
|
157
|
-
for (const router of this.routers.values()) {
|
|
158
|
-
yield* router.meta
|
|
159
|
-
}
|
|
160
|
-
for (const { procedure } of this.procedures.values()) {
|
|
161
|
-
yield procedure
|
|
162
|
-
yield* procedure.meta
|
|
163
|
-
yield* procedure.guards
|
|
164
|
-
yield* procedure.middlewares
|
|
104
|
+
return {
|
|
105
|
+
transports: createHostTransportConfig(
|
|
106
|
+
this.hostDefinition.transports,
|
|
107
|
+
this.runtimeOptions.transports,
|
|
108
|
+
),
|
|
109
|
+
gateway: this.hostDefinition.gateway,
|
|
110
|
+
identity: this.hostDefinition.identity,
|
|
165
111
|
}
|
|
166
112
|
}
|
|
113
|
+
}
|
|
167
114
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
this.routers.set(kRootRouter, router)
|
|
180
|
-
this.registerRouter(router, [])
|
|
181
|
-
|
|
182
|
-
if (router.default) {
|
|
183
|
-
if (!isProcedure(router.default)) {
|
|
184
|
-
throw new Error('Root router default must be a procedure')
|
|
185
|
-
}
|
|
186
|
-
this.procedures.set(kDefaultProcedure, {
|
|
187
|
-
procedure: router.default,
|
|
188
|
-
path: [router],
|
|
189
|
-
})
|
|
115
|
+
function createHostTransportConfig<
|
|
116
|
+
Transports extends Record<string, ApplicationTransport>,
|
|
117
|
+
>(
|
|
118
|
+
transports: Transports,
|
|
119
|
+
options: { [K in keyof Transports]: TransportOptionsOf<Transports[K]> },
|
|
120
|
+
) {
|
|
121
|
+
const config = {} as {
|
|
122
|
+
[K in keyof Transports]: {
|
|
123
|
+
transport: Transports[K]
|
|
124
|
+
options: TransportOptionsOf<Transports[K]>
|
|
190
125
|
}
|
|
191
|
-
|
|
192
|
-
for (const filter of filters) this.filters.add(filter)
|
|
193
|
-
for (const middleware of middlewares) this.middlewares.add(middleware)
|
|
194
|
-
for (const guard of guards) this.guards.add(guard)
|
|
195
126
|
}
|
|
196
127
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (isRouter(route)) {
|
|
200
|
-
const name = route.contract.name
|
|
201
|
-
if (!name) throw new Error('Nested routers must have a name')
|
|
202
|
-
if (this.routers.has(name)) {
|
|
203
|
-
throw new Error(`Router ${String(name)} already registered`)
|
|
204
|
-
}
|
|
205
|
-
this.routers.set(name, route)
|
|
206
|
-
this.registerRouter(route, [...path, router])
|
|
207
|
-
} else if (isProcedure(route)) {
|
|
208
|
-
const name = route.contract.name
|
|
209
|
-
if (!name) throw new Error('Procedures must have a name')
|
|
210
|
-
if (this.procedures.has(name)) {
|
|
211
|
-
throw new Error(`Procedure ${name} already registered`)
|
|
212
|
-
}
|
|
213
|
-
this.procedures.set(name, { procedure: route, path: [...path, router] })
|
|
214
|
-
}
|
|
215
|
-
}
|
|
128
|
+
for (const key in transports) {
|
|
129
|
+
config[key] = { transport: transports[key], options: options[key] }
|
|
216
130
|
}
|
|
131
|
+
|
|
132
|
+
return config
|
|
217
133
|
}
|