nmtjs 0.15.0-beta.2 → 0.15.0-beta.21
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.d.ts +2 -0
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -0
- package/dist/entrypoints/cli.d.ts +1 -0
- package/dist/entrypoints/cli.js +1 -0
- package/dist/entrypoints/cli.js.map +1 -0
- package/dist/entrypoints/main.d.ts +5 -0
- package/dist/entrypoints/main.js +83 -15
- package/dist/entrypoints/main.js.map +1 -0
- package/dist/entrypoints/thread.d.ts +14 -0
- package/dist/entrypoints/thread.js +130 -24
- package/dist/entrypoints/thread.js.map +1 -0
- package/dist/entrypoints/worker.d.ts +3 -0
- package/dist/entrypoints/worker.js +4 -3
- package/dist/entrypoints/worker.js.map +1 -0
- package/dist/index.d.ts +69 -0
- package/dist/{_exports/index.js → index.js} +9 -5
- package/dist/index.js.map +1 -0
- package/dist/resolver.d.ts +2 -0
- package/dist/resolver.js +1 -0
- package/dist/resolver.js.map +1 -0
- package/dist/runtime/application/api/api.d.ts +49 -0
- package/dist/runtime/application/api/api.js +193 -0
- package/dist/runtime/application/api/api.js.map +1 -0
- package/dist/runtime/application/api/constants.d.ts +14 -0
- package/dist/runtime/application/api/constants.js +8 -0
- package/dist/runtime/application/api/constants.js.map +1 -0
- package/dist/runtime/application/api/filters.d.ts +14 -0
- package/dist/runtime/application/api/filters.js +11 -0
- package/dist/runtime/application/api/filters.js.map +1 -0
- package/dist/runtime/application/api/guards.d.ts +13 -0
- package/dist/runtime/application/api/guards.js +8 -0
- package/dist/runtime/application/api/guards.js.map +1 -0
- package/dist/runtime/application/api/index.d.ts +8 -0
- package/dist/runtime/application/api/index.js +9 -0
- package/dist/runtime/application/api/index.js.map +1 -0
- package/dist/runtime/application/api/middlewares.d.ts +14 -0
- package/dist/runtime/application/api/middlewares.js +12 -0
- package/dist/runtime/application/api/middlewares.js.map +1 -0
- package/dist/runtime/application/api/procedure.d.ts +67 -0
- package/dist/runtime/application/api/procedure.js +50 -0
- package/dist/runtime/application/api/procedure.js.map +1 -0
- package/dist/runtime/application/api/router.d.ts +71 -0
- package/dist/runtime/application/api/router.js +51 -0
- package/dist/runtime/application/api/router.js.map +1 -0
- package/dist/runtime/application/api/types.d.ts +32 -0
- package/dist/runtime/application/api/types.js +2 -0
- package/dist/runtime/application/api/types.js.map +1 -0
- package/dist/runtime/application/config.d.ts +26 -0
- package/dist/runtime/application/config.js +21 -0
- package/dist/runtime/application/config.js.map +1 -0
- package/dist/runtime/application/constants.d.ts +2 -0
- package/dist/runtime/application/constants.js +2 -0
- package/dist/runtime/application/constants.js.map +1 -0
- package/dist/runtime/application/hook.d.ts +19 -0
- package/dist/runtime/application/hook.js +11 -0
- package/dist/runtime/application/hook.js.map +1 -0
- package/dist/runtime/application/hooks.d.ts +3 -0
- package/dist/runtime/application/hooks.js +4 -0
- package/dist/runtime/application/hooks.js.map +1 -0
- package/dist/runtime/application/index.d.ts +5 -0
- package/dist/runtime/application/index.js +6 -0
- package/dist/runtime/application/index.js.map +1 -0
- package/dist/runtime/constants.d.ts +8 -0
- package/dist/runtime/constants.js +5 -0
- package/dist/runtime/constants.js.map +1 -0
- package/dist/runtime/core/hooks.d.ts +4 -0
- package/dist/runtime/core/hooks.js +4 -0
- package/dist/runtime/core/hooks.js.map +1 -0
- package/dist/runtime/core/plugin.d.ts +8 -0
- package/dist/runtime/core/plugin.js +4 -0
- package/dist/runtime/core/plugin.js.map +1 -0
- package/dist/runtime/core/runtime.d.ts +27 -0
- package/dist/runtime/core/runtime.js +81 -0
- package/dist/runtime/core/runtime.js.map +1 -0
- package/dist/runtime/enums.d.ts +21 -0
- package/dist/runtime/enums.js +26 -0
- package/dist/runtime/enums.js.map +1 -0
- package/dist/runtime/index.d.ts +21 -0
- package/dist/runtime/index.js +22 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/injectables.d.ts +23 -0
- package/dist/runtime/injectables.js +20 -0
- package/dist/runtime/injectables.js.map +1 -0
- package/dist/runtime/jobs/job.d.ts +132 -0
- package/dist/runtime/jobs/job.js +68 -0
- package/dist/runtime/jobs/job.js.map +1 -0
- package/dist/runtime/jobs/manager.d.ts +113 -0
- package/dist/runtime/jobs/manager.js +210 -0
- package/dist/runtime/jobs/manager.js.map +1 -0
- package/dist/runtime/jobs/router.d.ts +266 -0
- package/dist/runtime/jobs/router.js +432 -0
- package/dist/runtime/jobs/router.js.map +1 -0
- package/dist/runtime/jobs/runner.d.ts +64 -0
- package/dist/runtime/jobs/runner.js +256 -0
- package/dist/runtime/jobs/runner.js.map +1 -0
- package/dist/runtime/jobs/step.d.ts +23 -0
- package/dist/runtime/jobs/step.js +18 -0
- package/dist/runtime/jobs/step.js.map +1 -0
- package/dist/runtime/jobs/ui.d.ts +3 -0
- package/dist/runtime/jobs/ui.js +17 -0
- package/dist/runtime/jobs/ui.js.map +1 -0
- package/dist/runtime/pubsub/manager.d.ts +48 -0
- package/dist/runtime/pubsub/manager.js +119 -0
- package/dist/runtime/pubsub/manager.js.map +1 -0
- package/dist/runtime/pubsub/redis.d.ts +16 -0
- package/dist/runtime/pubsub/redis.js +98 -0
- package/dist/runtime/pubsub/redis.js.map +1 -0
- package/dist/runtime/scheduler/index.d.ts +22 -0
- package/dist/runtime/scheduler/index.js +20 -0
- package/dist/runtime/scheduler/index.js.map +1 -0
- package/dist/runtime/server/applications.d.ts +52 -0
- package/dist/runtime/server/applications.js +133 -0
- package/dist/runtime/server/applications.js.map +1 -0
- package/dist/runtime/server/config.d.ts +121 -0
- package/dist/runtime/server/config.js +33 -0
- package/dist/runtime/server/config.js.map +1 -0
- package/dist/runtime/server/jobs.d.ts +41 -0
- package/dist/runtime/server/jobs.js +181 -0
- package/dist/runtime/server/jobs.js.map +1 -0
- package/dist/runtime/server/pool.d.ts +54 -0
- package/dist/runtime/server/pool.js +194 -0
- package/dist/runtime/server/pool.js.map +1 -0
- package/dist/runtime/server/proxy.d.ts +21 -0
- package/dist/runtime/server/proxy.js +79 -0
- package/dist/runtime/server/proxy.js.map +1 -0
- package/dist/runtime/server/server.d.ts +53 -0
- package/dist/runtime/server/server.js +90 -0
- package/dist/runtime/server/server.js.map +1 -0
- package/dist/runtime/store/index.d.ts +3 -0
- package/dist/runtime/store/index.js +23 -0
- package/dist/runtime/store/index.js.map +1 -0
- package/dist/runtime/types.d.ts +103 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/workers/application.d.ts +47 -0
- package/dist/runtime/workers/application.js +162 -0
- package/dist/runtime/workers/application.js.map +1 -0
- package/dist/runtime/workers/base.d.ts +16 -0
- package/dist/runtime/workers/base.js +46 -0
- package/dist/runtime/workers/base.js.map +1 -0
- package/dist/runtime/workers/cli.d.ts +1 -0
- package/dist/runtime/workers/cli.js +2 -0
- package/dist/runtime/workers/cli.js.map +1 -0
- package/dist/runtime/workers/job.d.ts +20 -0
- package/dist/runtime/workers/job.js +172 -0
- package/dist/runtime/workers/job.js.map +1 -0
- package/dist/typings.d.ts +5 -0
- package/dist/typings.js +4 -3
- package/dist/typings.js.map +1 -0
- package/dist/vite/builder.d.ts +5 -0
- package/dist/vite/builder.js +5 -1
- package/dist/vite/builder.js.map +1 -0
- package/dist/vite/config.d.ts +28 -0
- package/dist/vite/config.js +1 -0
- package/dist/vite/config.js.map +1 -0
- package/dist/vite/plugins.d.ts +2 -0
- package/dist/vite/plugins.js +1 -0
- package/dist/vite/plugins.js.map +1 -0
- package/dist/vite/runners/worker.d.ts +4 -0
- package/dist/vite/runners/worker.js +1 -0
- package/dist/vite/runners/worker.js.map +1 -0
- package/dist/vite/server.d.ts +3 -0
- package/dist/vite/server.js +6 -1
- package/dist/vite/server.js.map +1 -0
- package/dist/vite/servers/main.d.ts +8 -0
- package/dist/vite/servers/main.js +1 -0
- package/dist/vite/servers/main.js.map +1 -0
- package/dist/vite/servers/worker.d.ts +11 -0
- package/dist/vite/servers/worker.js +28 -0
- package/dist/vite/servers/worker.js.map +1 -0
- package/package.json +31 -18
- package/src/cli.ts +144 -0
- package/src/config.ts +64 -0
- package/src/entrypoints/cli.ts +13 -0
- package/src/entrypoints/main.ts +200 -0
- package/src/entrypoints/thread.ts +184 -0
- package/src/entrypoints/worker.ts +48 -0
- package/src/index.ts +82 -0
- package/src/resolver.ts +16 -0
- package/src/runtime/application/api/api.ts +265 -0
- package/src/runtime/application/api/constants.ts +22 -0
- package/src/runtime/application/api/filters.ts +39 -0
- package/src/runtime/application/api/guards.ts +29 -0
- package/src/runtime/application/api/index.ts +8 -0
- package/src/runtime/application/api/middlewares.ts +37 -0
- package/src/runtime/application/api/procedure.ts +229 -0
- package/src/runtime/application/api/router.ts +193 -0
- package/src/runtime/application/api/types.ts +124 -0
- package/src/runtime/application/config.ts +69 -0
- package/src/runtime/application/constants.ts +4 -0
- package/src/runtime/application/hook.ts +51 -0
- package/src/runtime/application/hooks.ts +3 -0
- package/src/runtime/application/index.ts +5 -0
- package/src/runtime/constants.ts +13 -0
- package/src/runtime/core/hooks.ts +5 -0
- package/src/runtime/core/plugin.ts +13 -0
- package/src/runtime/core/runtime.ts +109 -0
- package/src/runtime/enums.ts +24 -0
- package/src/runtime/index.ts +21 -0
- package/src/runtime/injectables.ts +61 -0
- package/src/runtime/jobs/job.ts +370 -0
- package/src/runtime/jobs/manager.ts +348 -0
- package/src/runtime/jobs/router.ts +896 -0
- package/src/runtime/jobs/runner.ts +320 -0
- package/src/runtime/jobs/step.ts +66 -0
- package/src/runtime/jobs/ui.ts +21 -0
- package/src/runtime/pubsub/manager.ts +211 -0
- package/src/runtime/pubsub/redis.ts +108 -0
- package/src/runtime/scheduler/index.ts +39 -0
- package/src/runtime/server/applications.ts +210 -0
- package/src/runtime/server/config.ts +158 -0
- package/src/runtime/server/jobs.ts +250 -0
- package/src/runtime/server/pool.ts +260 -0
- package/src/runtime/server/proxy.ts +118 -0
- package/src/runtime/server/server.ts +155 -0
- package/src/runtime/store/index.ts +30 -0
- package/src/runtime/types.ts +93 -0
- package/src/runtime/workers/application.ts +209 -0
- package/src/runtime/workers/base.ts +68 -0
- package/src/runtime/workers/cli.ts +0 -0
- package/src/runtime/workers/job.ts +153 -0
- package/src/typings.ts +30 -0
- package/src/vite/builder.ts +122 -0
- package/src/vite/config.ts +45 -0
- package/src/vite/plugins.ts +26 -0
- package/src/vite/runners/worker.ts +57 -0
- package/src/vite/server.ts +39 -0
- package/src/vite/servers/main.ts +34 -0
- package/src/vite/servers/worker.ts +143 -0
- package/dist/_exports/application.js +0 -1
- package/dist/_exports/common.js +0 -1
- package/dist/_exports/contract.js +0 -2
- package/dist/_exports/core.js +0 -1
- package/dist/_exports/gateway.js +0 -1
- package/dist/_exports/http-transport/bun.js +0 -1
- package/dist/_exports/http-transport/deno.js +0 -1
- package/dist/_exports/http-transport/node.js +0 -1
- package/dist/_exports/http-transport.js +0 -1
- package/dist/_exports/json-format.js +0 -1
- package/dist/_exports/protocol/client.js +0 -1
- package/dist/_exports/protocol/server.js +0 -1
- package/dist/_exports/protocol.js +0 -1
- package/dist/_exports/runtime/types.js +0 -1
- package/dist/_exports/runtime.js +0 -1
- package/dist/_exports/type.js +0 -2
- package/dist/_exports/ws-transport/bun.js +0 -1
- package/dist/_exports/ws-transport/deno.js +0 -1
- package/dist/_exports/ws-transport/node.js +0 -1
- package/dist/_exports/ws-transport.js +0 -1
- package/dist/command.js +0 -30
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type EventEmitter from 'node:events'
|
|
2
|
+
import type { Worker } from 'node:worker_threads'
|
|
3
|
+
|
|
4
|
+
import type { Logger } from '@nmtjs/core'
|
|
5
|
+
import { createLogger } from '@nmtjs/core'
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
Store,
|
|
9
|
+
ThreadPortMessageTypes,
|
|
10
|
+
WorkerThreadError,
|
|
11
|
+
} from '../types.ts'
|
|
12
|
+
import type { ServerConfig } from './config.ts'
|
|
13
|
+
import { createStoreClient } from '../store/index.ts'
|
|
14
|
+
import { ApplicationServerApplications } from './applications.ts'
|
|
15
|
+
import { ApplicationServerJobs } from './jobs.ts'
|
|
16
|
+
import { ApplicationServerProxy } from './proxy.ts'
|
|
17
|
+
|
|
18
|
+
export type ApplicationServerRunOptions = {
|
|
19
|
+
applications: string[]
|
|
20
|
+
scheduler: boolean
|
|
21
|
+
jobs: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type ApplicationWorkerReadyEvent = {
|
|
25
|
+
application: string
|
|
26
|
+
threadId: number
|
|
27
|
+
hosts?: ThreadPortMessageTypes['ready']['hosts']
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ApplicationWorkerErrorEvent = {
|
|
31
|
+
application: string
|
|
32
|
+
threadId: number
|
|
33
|
+
error: WorkerThreadError
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ApplicationServerWorkerConfig = {
|
|
37
|
+
path: string
|
|
38
|
+
workerData?: any
|
|
39
|
+
worker?: (worker: Worker) => any
|
|
40
|
+
events?: EventEmitter<{
|
|
41
|
+
worker: [Worker]
|
|
42
|
+
'worker-ready': [ApplicationWorkerReadyEvent]
|
|
43
|
+
'worker-error': [ApplicationWorkerErrorEvent]
|
|
44
|
+
}>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class ApplicationServer {
|
|
48
|
+
logger: Logger
|
|
49
|
+
|
|
50
|
+
applications?: ApplicationServerApplications
|
|
51
|
+
jobRunners?: ApplicationServerJobs
|
|
52
|
+
|
|
53
|
+
proxy?: ApplicationServerProxy
|
|
54
|
+
store?: Store
|
|
55
|
+
|
|
56
|
+
constructor(
|
|
57
|
+
readonly config: ServerConfig,
|
|
58
|
+
readonly applicationsConfig: Record<
|
|
59
|
+
string,
|
|
60
|
+
{ type: 'neemata' | 'custom'; specifier: string }
|
|
61
|
+
>,
|
|
62
|
+
readonly workerConfig: ApplicationServerWorkerConfig,
|
|
63
|
+
readonly runOptions: ApplicationServerRunOptions = {
|
|
64
|
+
applications: Object.keys(config.applications),
|
|
65
|
+
scheduler: false,
|
|
66
|
+
jobs: Boolean(config.jobs?.jobs.size),
|
|
67
|
+
},
|
|
68
|
+
) {
|
|
69
|
+
this.logger = createLogger(config.logger, 'Server')
|
|
70
|
+
this.logger.trace(
|
|
71
|
+
{ applications: applicationsConfig, workerConfig, runOptions },
|
|
72
|
+
'ApplicationServer initialized',
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async start() {
|
|
77
|
+
const { config, logger } = this
|
|
78
|
+
logger.info('Starting application server...')
|
|
79
|
+
|
|
80
|
+
if (config.store) {
|
|
81
|
+
this.store = await createStoreClient(config.store)
|
|
82
|
+
await this.store.connect()
|
|
83
|
+
logger.debug('Store connected')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.applications = new ApplicationServerApplications({
|
|
87
|
+
logger: this.logger,
|
|
88
|
+
workerConfig: this.workerConfig,
|
|
89
|
+
serverConfig: this.config,
|
|
90
|
+
applicationsConfig: this.applicationsConfig,
|
|
91
|
+
applications: this.runOptions.applications,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if (this.runOptions.jobs) {
|
|
95
|
+
if (!this.store) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
'Jobs feature requires a store configuration. ' +
|
|
98
|
+
'Please configure `store` in your server config or disable jobs.',
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
this.jobRunners = new ApplicationServerJobs({
|
|
102
|
+
logger: this.logger,
|
|
103
|
+
workerConfig: this.workerConfig,
|
|
104
|
+
serverConfig: this.config,
|
|
105
|
+
store: this.store,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.config.proxy) {
|
|
110
|
+
this.proxy = new ApplicationServerProxy({
|
|
111
|
+
logger: this.logger,
|
|
112
|
+
config: this.config.proxy,
|
|
113
|
+
applications: this.applications,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await this.applications.start()
|
|
118
|
+
|
|
119
|
+
if (this.runOptions.jobs) {
|
|
120
|
+
await this.jobRunners?.start()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (this.runOptions.scheduler && config.jobs?.scheduler) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
'JobsScheduler is currently a work in progress and not available. ' +
|
|
126
|
+
'Scheduled jobs will be supported in a future release.',
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (this.proxy) {
|
|
131
|
+
await this.proxy.start()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
logger.info('Application server started')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async stop() {
|
|
138
|
+
this.logger.info('Stopping application server...')
|
|
139
|
+
|
|
140
|
+
// Stop proxy + stop accepting new jobs first
|
|
141
|
+
await this.proxy?.stop()
|
|
142
|
+
await this.jobRunners?.stop()
|
|
143
|
+
|
|
144
|
+
// Stop applications
|
|
145
|
+
await this.applications?.stop()
|
|
146
|
+
|
|
147
|
+
// Close store connection
|
|
148
|
+
if (this.store) {
|
|
149
|
+
this.logger.debug('Closing store...')
|
|
150
|
+
this.store.disconnect(false)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.logger.info('Application server stopped')
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ServerStoreConfig } from '../server/config.ts'
|
|
2
|
+
import type { StoreTypes } from '../types.ts'
|
|
3
|
+
import { StoreType } from '../enums.ts'
|
|
4
|
+
|
|
5
|
+
export async function createStoreClient<T extends ServerStoreConfig>(
|
|
6
|
+
config: T,
|
|
7
|
+
): Promise<StoreTypes[T['type']]> {
|
|
8
|
+
if (config.type === StoreType.Redis) {
|
|
9
|
+
const { Redis } = await import('ioredis').catch(() => {
|
|
10
|
+
throw new Error(
|
|
11
|
+
'ioredis package is not installed. Please install it to use Redis store.',
|
|
12
|
+
)
|
|
13
|
+
})
|
|
14
|
+
return new Redis({
|
|
15
|
+
...config.options,
|
|
16
|
+
lazyConnect: true,
|
|
17
|
+
}) as StoreTypes[T['type']]
|
|
18
|
+
} else if (config.type === StoreType.Valkey) {
|
|
19
|
+
const { Redis } = await import('iovalkey').catch(() => {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'iovalkey package is not installed. Please install it to use Valkey store.',
|
|
22
|
+
)
|
|
23
|
+
})
|
|
24
|
+
return new Redis({
|
|
25
|
+
...config.options,
|
|
26
|
+
lazyConnect: true,
|
|
27
|
+
}) as StoreTypes[T['type']]
|
|
28
|
+
}
|
|
29
|
+
throw new Error('Unsupported store')
|
|
30
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { HookTypes } from '@nmtjs/core'
|
|
2
|
+
import type { ProxyableTransportType } from '@nmtjs/gateway'
|
|
3
|
+
import type { Redis, RedisOptions } from 'ioredis'
|
|
4
|
+
import type { Redis as Valkey, RedisOptions as ValkeyOptions } from 'iovalkey'
|
|
5
|
+
|
|
6
|
+
import type { ApplicationConfig } from './application/config.ts'
|
|
7
|
+
import type { BaseRuntime } from './core/runtime.ts'
|
|
8
|
+
import type { LifecycleHook, StoreType } from './enums.ts'
|
|
9
|
+
|
|
10
|
+
export type WorkerThreadErrorOrigin = 'bootstrap' | 'start' | 'runtime'
|
|
11
|
+
|
|
12
|
+
export type ThreadErrorMessage = {
|
|
13
|
+
message: string
|
|
14
|
+
name?: string
|
|
15
|
+
stack?: string
|
|
16
|
+
origin: WorkerThreadErrorOrigin
|
|
17
|
+
fatal: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type WorkerThreadError = Error & {
|
|
21
|
+
origin?: WorkerThreadErrorOrigin
|
|
22
|
+
fatal?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ServerPortMessageTypes = {
|
|
26
|
+
stop: undefined
|
|
27
|
+
task: { id: string; task: WorkerJobTask }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type ThreadPortMessageTypes = {
|
|
31
|
+
ready: { hosts?: { type: ProxyableTransportType; url: string }[] }
|
|
32
|
+
error: ThreadErrorMessage
|
|
33
|
+
task: { id: string; task: JobTaskResult }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ServerPortMessage = {
|
|
37
|
+
[K in keyof ServerPortMessageTypes]: {
|
|
38
|
+
type: K
|
|
39
|
+
data: ServerPortMessageTypes[K]
|
|
40
|
+
}
|
|
41
|
+
}[keyof ServerPortMessageTypes]
|
|
42
|
+
|
|
43
|
+
export type ThreadPortMessage = {
|
|
44
|
+
[K in keyof ThreadPortMessageTypes]: {
|
|
45
|
+
type: K
|
|
46
|
+
data: ThreadPortMessageTypes[K]
|
|
47
|
+
}
|
|
48
|
+
}[keyof ThreadPortMessageTypes]
|
|
49
|
+
|
|
50
|
+
export interface WorkerTask {
|
|
51
|
+
type?: string
|
|
52
|
+
payload?: any
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type WorkerJobTask = { jobId: string; jobName: string; data: any }
|
|
56
|
+
|
|
57
|
+
export type JobTaskResult = {
|
|
58
|
+
[K in keyof JobTaskResultTypes]: { type: K } & JobTaskResultTypes[K]
|
|
59
|
+
}[keyof JobTaskResultTypes]
|
|
60
|
+
|
|
61
|
+
export type JobTaskResultTypes = {
|
|
62
|
+
success: { result?: unknown }
|
|
63
|
+
error: { error: any }
|
|
64
|
+
unrecoverable_error: { error: any }
|
|
65
|
+
job_not_found: {}
|
|
66
|
+
queue_job_not_found: {}
|
|
67
|
+
}
|
|
68
|
+
|
|
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
|
+
export type ApplicationDefinitionType =
|
|
77
|
+
| { type: 'neemata'; definition: ApplicationConfig<any, any> }
|
|
78
|
+
| { type: 'custom'; definition: any }
|
|
79
|
+
|
|
80
|
+
export interface Applications
|
|
81
|
+
extends Record<string, ApplicationDefinitionType> {}
|
|
82
|
+
|
|
83
|
+
export type StoreTypes = {
|
|
84
|
+
[StoreType.Redis]: Redis
|
|
85
|
+
[StoreType.Valkey]: Valkey
|
|
86
|
+
}
|
|
87
|
+
export type StoreTypeOptions = {
|
|
88
|
+
[StoreType.Redis]: RedisOptions
|
|
89
|
+
[StoreType.Valkey]: ValkeyOptions
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type Store = StoreTypes[StoreType]
|
|
93
|
+
export type StoreOptions = StoreTypeOptions[StoreType]
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { Dependant } from '@nmtjs/core'
|
|
2
|
+
import type { GatewayOptions, Transport } from '@nmtjs/gateway'
|
|
3
|
+
import { Gateway } from '@nmtjs/gateway'
|
|
4
|
+
import { JsonFormat } from '@nmtjs/json-format/server'
|
|
5
|
+
import { ProtocolFormats } from '@nmtjs/protocol/server'
|
|
6
|
+
|
|
7
|
+
import type { ApplicationConfig } from '../application/config.ts'
|
|
8
|
+
import type {
|
|
9
|
+
AnyFilter,
|
|
10
|
+
AnyGuard,
|
|
11
|
+
AnyMiddleware,
|
|
12
|
+
AnyProcedure,
|
|
13
|
+
AnyRouter,
|
|
14
|
+
kDefaultProcedure as kDefaultProcedureKey,
|
|
15
|
+
} from '../application/index.ts'
|
|
16
|
+
import type { ServerConfig } from '../server/config.ts'
|
|
17
|
+
import { ApplicationApi } from '../application/api/api.ts'
|
|
18
|
+
import { ApplicationHooks } from '../application/hooks.ts'
|
|
19
|
+
import {
|
|
20
|
+
isProcedure,
|
|
21
|
+
isRootRouter,
|
|
22
|
+
isRouter,
|
|
23
|
+
kDefaultProcedure,
|
|
24
|
+
kRootRouter,
|
|
25
|
+
} from '../application/index.ts'
|
|
26
|
+
import { LifecycleHook, WorkerType } from '../enums.ts'
|
|
27
|
+
import { BaseWorkerRuntime } from './base.ts'
|
|
28
|
+
|
|
29
|
+
export interface ApplicationWorkerRuntimeOptions {
|
|
30
|
+
name: string
|
|
31
|
+
path: string
|
|
32
|
+
transports: { [key: string]: any }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class ApplicationWorkerRuntime extends BaseWorkerRuntime {
|
|
36
|
+
api!: ApplicationApi
|
|
37
|
+
applicationHooks!: ApplicationHooks
|
|
38
|
+
gateway!: Gateway
|
|
39
|
+
transports!: GatewayOptions['transports']
|
|
40
|
+
|
|
41
|
+
routers = new Map<string | kRootRouter, AnyRouter>()
|
|
42
|
+
procedures = new Map<
|
|
43
|
+
string | kDefaultProcedureKey,
|
|
44
|
+
{ procedure: AnyProcedure; path: AnyRouter[] }
|
|
45
|
+
>()
|
|
46
|
+
filters = new Set<AnyFilter>()
|
|
47
|
+
middlewares = new Set<AnyMiddleware>()
|
|
48
|
+
guards = new Set<AnyGuard>()
|
|
49
|
+
|
|
50
|
+
constructor(
|
|
51
|
+
readonly config: ServerConfig,
|
|
52
|
+
readonly runtimeOptions: ApplicationWorkerRuntimeOptions,
|
|
53
|
+
protected appConfig: ApplicationConfig,
|
|
54
|
+
) {
|
|
55
|
+
super(
|
|
56
|
+
config,
|
|
57
|
+
{
|
|
58
|
+
logger: config.logger,
|
|
59
|
+
name: `Worker ${runtimeOptions.name}`,
|
|
60
|
+
plugins: appConfig.plugins,
|
|
61
|
+
},
|
|
62
|
+
WorkerType.Application,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
this.applicationHooks = new ApplicationHooks()
|
|
66
|
+
|
|
67
|
+
this.api = new ApplicationApi({
|
|
68
|
+
timeout: this.appConfig.api.timeout,
|
|
69
|
+
container: this.container,
|
|
70
|
+
logger: this.logger,
|
|
71
|
+
filters: this.filters,
|
|
72
|
+
middlewares: this.middlewares,
|
|
73
|
+
guards: this.guards,
|
|
74
|
+
procedures: this.procedures,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async start() {
|
|
79
|
+
await this.initialize()
|
|
80
|
+
|
|
81
|
+
this.transports = {}
|
|
82
|
+
|
|
83
|
+
for (const key in this.runtimeOptions.transports) {
|
|
84
|
+
const options = this.runtimeOptions.transports[key]
|
|
85
|
+
const { factory, proxyable } = this.appConfig.transports[key] as Transport
|
|
86
|
+
this.transports[key] = { transport: await factory(options), proxyable }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.gateway = new Gateway({
|
|
90
|
+
logger: this.logger,
|
|
91
|
+
container: this.container,
|
|
92
|
+
hooks: this.lifecycleHooks,
|
|
93
|
+
formats: new ProtocolFormats([new JsonFormat()]),
|
|
94
|
+
transports: this.transports,
|
|
95
|
+
api: this.api,
|
|
96
|
+
identity: this.appConfig.identity,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
return await this.gateway.start().finally(async () => {
|
|
100
|
+
await this.lifecycleHooks.callHook(LifecycleHook.Start)
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async stop() {
|
|
105
|
+
await this.gateway.stop()
|
|
106
|
+
await this.dispose()
|
|
107
|
+
await this.lifecycleHooks.callHook(LifecycleHook.Stop)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async reload(appConfig: ApplicationConfig): Promise<void> {
|
|
111
|
+
await this.dispose()
|
|
112
|
+
this.appConfig = appConfig
|
|
113
|
+
this.plugins = appConfig.plugins
|
|
114
|
+
await this.initialize()
|
|
115
|
+
this.gateway.options.identity =
|
|
116
|
+
this.appConfig.identity ?? this.gateway.options.identity
|
|
117
|
+
await this.gateway.reload()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async initialize(): Promise<void> {
|
|
121
|
+
this.registerApi()
|
|
122
|
+
this.lifecycleHooks.addHooks(this.appConfig.lifecycleHooks)
|
|
123
|
+
await super.initialize()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
protected async _initialize(): Promise<void> {
|
|
127
|
+
await super._initialize()
|
|
128
|
+
|
|
129
|
+
for (const hook of this.appConfig.hooks) {
|
|
130
|
+
this.applicationHooks.hook(hook.name, async (...args: any[]) => {
|
|
131
|
+
const ctx = await this.container.createContext(hook.dependencies)
|
|
132
|
+
await hook.handler(ctx, ...args)
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
protected async _dispose(): Promise<void> {
|
|
138
|
+
this.applicationHooks.removeAllHooks()
|
|
139
|
+
await super._dispose()
|
|
140
|
+
this.lifecycleHooks.removeHooks(this.appConfig.lifecycleHooks)
|
|
141
|
+
this.filters.clear()
|
|
142
|
+
this.middlewares.clear()
|
|
143
|
+
this.guards.clear()
|
|
144
|
+
this.routers.clear()
|
|
145
|
+
this.procedures.clear()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
protected *_dependents(): Generator<Dependant> {
|
|
149
|
+
yield* this.appConfig.filters
|
|
150
|
+
yield* this.appConfig.guards
|
|
151
|
+
yield* this.appConfig.middlewares
|
|
152
|
+
yield* this.appConfig.hooks
|
|
153
|
+
for (const { procedure } of this.procedures.values()) {
|
|
154
|
+
yield procedure
|
|
155
|
+
yield* procedure.guards
|
|
156
|
+
yield* procedure.middlewares
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
protected registerApi() {
|
|
161
|
+
const { router, filters, guards, middlewares } = this.appConfig
|
|
162
|
+
|
|
163
|
+
if (this.routers.has(kRootRouter)) {
|
|
164
|
+
throw new Error('Root router already registered')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!isRootRouter(router)) {
|
|
168
|
+
throw new Error('Root router must be a root router')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.routers.set(kRootRouter, router)
|
|
172
|
+
this.registerRouter(router, [])
|
|
173
|
+
|
|
174
|
+
if (router.default) {
|
|
175
|
+
if (!isProcedure(router.default)) {
|
|
176
|
+
throw new Error('Root router default must be a procedure')
|
|
177
|
+
}
|
|
178
|
+
this.procedures.set(kDefaultProcedure, {
|
|
179
|
+
procedure: router.default,
|
|
180
|
+
path: [router],
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for (const filter of filters) this.filters.add(filter)
|
|
185
|
+
for (const middleware of middlewares) this.middlewares.add(middleware)
|
|
186
|
+
for (const guard of guards) this.guards.add(guard)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
protected registerRouter(router: AnyRouter, path: AnyRouter[] = []) {
|
|
190
|
+
for (const route of Object.values(router.routes)) {
|
|
191
|
+
if (isRouter(route)) {
|
|
192
|
+
const name = route.contract.name
|
|
193
|
+
if (!name) throw new Error('Nested routers must have a name')
|
|
194
|
+
if (this.routers.has(name)) {
|
|
195
|
+
throw new Error(`Router ${String(name)} already registered`)
|
|
196
|
+
}
|
|
197
|
+
this.routers.set(name, route)
|
|
198
|
+
this.registerRouter(route, [...path, router])
|
|
199
|
+
} else if (isProcedure(route)) {
|
|
200
|
+
const name = route.contract.name
|
|
201
|
+
if (!name) throw new Error('Procedures must have a name')
|
|
202
|
+
if (this.procedures.has(name)) {
|
|
203
|
+
throw new Error(`Procedure ${name} already registered`)
|
|
204
|
+
}
|
|
205
|
+
this.procedures.set(name, { procedure: route, path: [...path, router] })
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Injection } from '@nmtjs/core'
|
|
2
|
+
import { CoreInjectables, provide } from '@nmtjs/core'
|
|
3
|
+
|
|
4
|
+
import type { BaseRuntimeOptions } from '../core/runtime.ts'
|
|
5
|
+
import type { WorkerType } from '../enums.ts'
|
|
6
|
+
import type { ServerConfig } from '../server/config.ts'
|
|
7
|
+
import { BaseRuntime } from '../core/runtime.ts'
|
|
8
|
+
import * as injectables from '../injectables.ts'
|
|
9
|
+
import { JobManager } from '../jobs/manager.ts'
|
|
10
|
+
import { PubSubManager } from '../pubsub/manager.ts'
|
|
11
|
+
|
|
12
|
+
export abstract class BaseWorkerRuntime extends BaseRuntime {
|
|
13
|
+
pubsub: PubSubManager
|
|
14
|
+
jobManager?: JobManager
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
readonly config: ServerConfig,
|
|
18
|
+
options: BaseRuntimeOptions,
|
|
19
|
+
readonly workerType: WorkerType,
|
|
20
|
+
) {
|
|
21
|
+
super(options)
|
|
22
|
+
|
|
23
|
+
this.pubsub = new PubSubManager({
|
|
24
|
+
logger: this.logger,
|
|
25
|
+
container: this.container,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (this.config.store) {
|
|
29
|
+
this.jobManager = new JobManager(
|
|
30
|
+
this.config.store,
|
|
31
|
+
this.config.jobs ? Array.from(this.config.jobs.jobs.values()) : [],
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async initialize(): Promise<void> {
|
|
37
|
+
const injections: Injection[] = [
|
|
38
|
+
provide(CoreInjectables.logger, this.logger),
|
|
39
|
+
provide(injectables.workerType, this.workerType),
|
|
40
|
+
provide(injectables.pubSubPublish, this.pubsub.publish.bind(this.pubsub)),
|
|
41
|
+
provide(
|
|
42
|
+
injectables.pubSubSubscribe,
|
|
43
|
+
this.pubsub.subscribe.bind(this.pubsub),
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
if (this.config.store) {
|
|
48
|
+
injections.push(provide(injectables.storeConfig, this.config.store))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (this.jobManager) {
|
|
52
|
+
injections.push(
|
|
53
|
+
provide(injectables.jobManager, this.jobManager.publicInstance),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await this.container.provide(injections)
|
|
58
|
+
await super.initialize()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected async _initialize(): Promise<void> {
|
|
62
|
+
await this.jobManager?.initialize()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected async _dispose(): Promise<void> {
|
|
66
|
+
await this.jobManager?.terminate()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { MessagePort } from 'node:worker_threads'
|
|
2
|
+
|
|
3
|
+
import { UnrecoverableError } from 'bullmq'
|
|
4
|
+
|
|
5
|
+
import type { JobWorkerPool } from '../enums.ts'
|
|
6
|
+
import type { StepResultEntry } from '../jobs/runner.ts'
|
|
7
|
+
import type { ServerConfig } from '../server/config.ts'
|
|
8
|
+
import type { ServerPortMessage, ThreadPortMessage } from '../types.ts'
|
|
9
|
+
import { LifecycleHook, WorkerType } from '../enums.ts'
|
|
10
|
+
import { jobWorkerPool } from '../injectables.ts'
|
|
11
|
+
import { ApplicationWorkerJobRunner } from '../jobs/runner.ts'
|
|
12
|
+
import { BaseWorkerRuntime } from './base.ts'
|
|
13
|
+
|
|
14
|
+
export interface JobWorkerRuntimeOptions {
|
|
15
|
+
poolName: string
|
|
16
|
+
port: MessagePort
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class JobWorkerRuntime extends BaseWorkerRuntime {
|
|
20
|
+
jobRunner!: ApplicationWorkerJobRunner
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
readonly config: ServerConfig,
|
|
24
|
+
readonly runtimeOptions: JobWorkerRuntimeOptions,
|
|
25
|
+
) {
|
|
26
|
+
super(
|
|
27
|
+
config,
|
|
28
|
+
{ logger: config.logger, name: `Job Worker ${runtimeOptions.poolName}` },
|
|
29
|
+
WorkerType.Job,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async start() {
|
|
34
|
+
await this.initialize()
|
|
35
|
+
await this.lifecycleHooks.callHook(LifecycleHook.Start)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async stop() {
|
|
39
|
+
await this.lifecycleHooks.callHook(LifecycleHook.Stop)
|
|
40
|
+
await this.dispose()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async initialize(): Promise<void> {
|
|
44
|
+
// Validate all jobs are complete before accepting work
|
|
45
|
+
if (this.config.jobs) {
|
|
46
|
+
for (const job of this.config.jobs.jobs.values()) {
|
|
47
|
+
if (!job.returnHandler) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Job "${job.name}" is incomplete. Jobs must call .return() to be finalized before use.`,
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await this.container.provide(
|
|
56
|
+
jobWorkerPool,
|
|
57
|
+
this.runtimeOptions.poolName as JobWorkerPool,
|
|
58
|
+
)
|
|
59
|
+
await super.initialize()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
protected async _initialize(): Promise<void> {
|
|
63
|
+
await super._initialize()
|
|
64
|
+
|
|
65
|
+
this.jobRunner = new ApplicationWorkerJobRunner({
|
|
66
|
+
logger: this.logger,
|
|
67
|
+
container: this.container,
|
|
68
|
+
lifecycleHooks: this.lifecycleHooks,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
this.runtimeOptions.port.on('message', async (msg: ServerPortMessage) => {
|
|
72
|
+
if (msg.type === 'task') {
|
|
73
|
+
const { id, task } = msg.data
|
|
74
|
+
try {
|
|
75
|
+
const job = this.config.jobs?.jobs.get(task.jobName)
|
|
76
|
+
if (!job) {
|
|
77
|
+
this.runtimeOptions.port.postMessage({
|
|
78
|
+
type: 'task',
|
|
79
|
+
data: { id, task: { type: 'job_not_found' } },
|
|
80
|
+
} satisfies ThreadPortMessage)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
using cancellationSignal = this.jobManager!.cancellationSignal(
|
|
85
|
+
job,
|
|
86
|
+
task.jobId,
|
|
87
|
+
)
|
|
88
|
+
const queue = this.jobManager!.getQueue(job).queue
|
|
89
|
+
const bullJob = await queue.getJob(task.jobId)
|
|
90
|
+
if (!bullJob) {
|
|
91
|
+
throw new UnrecoverableError(
|
|
92
|
+
`Job ${task.jobId} not found in queue (may have been removed)`,
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Load checkpoint from BullMQ progress for resume support
|
|
97
|
+
const checkpoint = bullJob.progress as
|
|
98
|
+
| {
|
|
99
|
+
stepIndex: number
|
|
100
|
+
result: Record<string, unknown>
|
|
101
|
+
stepResults: StepResultEntry[]
|
|
102
|
+
progress: Record<string, unknown>
|
|
103
|
+
}
|
|
104
|
+
| undefined
|
|
105
|
+
|
|
106
|
+
const result = await this.jobRunner.runJob(job, task.data, {
|
|
107
|
+
signal: cancellationSignal,
|
|
108
|
+
queueJob: bullJob,
|
|
109
|
+
result: checkpoint?.result,
|
|
110
|
+
stepResults: checkpoint?.stepResults,
|
|
111
|
+
currentStepIndex: checkpoint?.stepIndex ?? 0,
|
|
112
|
+
progress: checkpoint?.progress,
|
|
113
|
+
})
|
|
114
|
+
this.runtimeOptions.port.postMessage({
|
|
115
|
+
type: 'task',
|
|
116
|
+
data: { id, task: { type: 'success', result } },
|
|
117
|
+
})
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error instanceof UnrecoverableError) {
|
|
120
|
+
this.runtimeOptions.port.postMessage({
|
|
121
|
+
type: 'task',
|
|
122
|
+
data: {
|
|
123
|
+
id,
|
|
124
|
+
task: { type: 'unrecoverable_error', error: error.message },
|
|
125
|
+
},
|
|
126
|
+
} satisfies ThreadPortMessage)
|
|
127
|
+
} else {
|
|
128
|
+
this.runtimeOptions.port.postMessage({
|
|
129
|
+
type: 'task',
|
|
130
|
+
data: { id, task: { type: 'error', error } },
|
|
131
|
+
} satisfies ThreadPortMessage)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
protected async _dispose(): Promise<void> {
|
|
139
|
+
this.runtimeOptions.port.removeAllListeners('message')
|
|
140
|
+
await super._dispose()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
protected *_dependents() {
|
|
144
|
+
if (this.config.jobs) {
|
|
145
|
+
for (const job of this.config.jobs.jobs.values()) {
|
|
146
|
+
yield job
|
|
147
|
+
// we explicitly DO NOT WANT to yield steps here, so per-job container
|
|
148
|
+
// resolves them independently each time — creates more isolation
|
|
149
|
+
// yield* job.steps
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|