nmtjs 0.16.1 → 0.17.0-beta.2

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.
Files changed (224) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +41 -1
  3. package/dist/index.d.ts +22 -161
  4. package/dist/index.js +24 -53
  5. package/dist/index.js.map +1 -1
  6. package/package.json +11 -63
  7. package/src/index.ts +71 -91
  8. package/bin/cli.js +0 -2
  9. package/dist/cli.d.ts +0 -1
  10. package/dist/cli.js +0 -137
  11. package/dist/cli.js.map +0 -1
  12. package/dist/codegen.d.ts +0 -5
  13. package/dist/codegen.js +0 -18
  14. package/dist/codegen.js.map +0 -1
  15. package/dist/config.d.ts +0 -47
  16. package/dist/config.js +0 -16
  17. package/dist/config.js.map +0 -1
  18. package/dist/entrypoints/cli.d.ts +0 -1
  19. package/dist/entrypoints/cli.js +0 -12
  20. package/dist/entrypoints/cli.js.map +0 -1
  21. package/dist/entrypoints/main.d.ts +0 -5
  22. package/dist/entrypoints/main.js +0 -248
  23. package/dist/entrypoints/main.js.map +0 -1
  24. package/dist/entrypoints/thread.d.ts +0 -16
  25. package/dist/entrypoints/thread.js +0 -182
  26. package/dist/entrypoints/thread.js.map +0 -1
  27. package/dist/entrypoints/worker.d.ts +0 -9
  28. package/dist/entrypoints/worker.js +0 -143
  29. package/dist/entrypoints/worker.js.map +0 -1
  30. package/dist/resolver.d.ts +0 -2
  31. package/dist/resolver.js +0 -7
  32. package/dist/resolver.js.map +0 -1
  33. package/dist/runtime/application/index.d.ts +0 -1
  34. package/dist/runtime/application/index.js +0 -2
  35. package/dist/runtime/application/index.js.map +0 -1
  36. package/dist/runtime/constants.d.ts +0 -8
  37. package/dist/runtime/constants.js +0 -5
  38. package/dist/runtime/constants.js.map +0 -1
  39. package/dist/runtime/enums.d.ts +0 -10
  40. package/dist/runtime/enums.js +0 -13
  41. package/dist/runtime/enums.js.map +0 -1
  42. package/dist/runtime/hooks.d.ts +0 -1
  43. package/dist/runtime/hooks.js +0 -2
  44. package/dist/runtime/hooks.js.map +0 -1
  45. package/dist/runtime/index.d.ts +0 -28
  46. package/dist/runtime/index.js +0 -29
  47. package/dist/runtime/index.js.map +0 -1
  48. package/dist/runtime/injectables.d.ts +0 -69
  49. package/dist/runtime/injectables.js +0 -40
  50. package/dist/runtime/injectables.js.map +0 -1
  51. package/dist/runtime/jobs/job.d.ts +0 -146
  52. package/dist/runtime/jobs/job.js +0 -89
  53. package/dist/runtime/jobs/job.js.map +0 -1
  54. package/dist/runtime/jobs/manager.d.ts +0 -131
  55. package/dist/runtime/jobs/manager.js +0 -309
  56. package/dist/runtime/jobs/manager.js.map +0 -1
  57. package/dist/runtime/jobs/router.d.ts +0 -296
  58. package/dist/runtime/jobs/router.js +0 -458
  59. package/dist/runtime/jobs/router.js.map +0 -1
  60. package/dist/runtime/jobs/runner.d.ts +0 -103
  61. package/dist/runtime/jobs/runner.js +0 -425
  62. package/dist/runtime/jobs/runner.js.map +0 -1
  63. package/dist/runtime/jobs/step.d.ts +0 -26
  64. package/dist/runtime/jobs/step.js +0 -18
  65. package/dist/runtime/jobs/step.js.map +0 -1
  66. package/dist/runtime/jobs/types.d.ts +0 -86
  67. package/dist/runtime/jobs/types.js +0 -5
  68. package/dist/runtime/jobs/types.js.map +0 -1
  69. package/dist/runtime/metrics/metric.d.ts +0 -8
  70. package/dist/runtime/metrics/metric.js +0 -11
  71. package/dist/runtime/metrics/metric.js.map +0 -1
  72. package/dist/runtime/metrics/registry.d.ts +0 -3
  73. package/dist/runtime/metrics/registry.js +0 -5
  74. package/dist/runtime/metrics/registry.js.map +0 -1
  75. package/dist/runtime/metrics/server.d.ts +0 -7
  76. package/dist/runtime/metrics/server.js +0 -53
  77. package/dist/runtime/metrics/server.js.map +0 -1
  78. package/dist/runtime/plugin.d.ts +0 -2
  79. package/dist/runtime/plugin.js +0 -2
  80. package/dist/runtime/plugin.js.map +0 -1
  81. package/dist/runtime/runtime.d.ts +0 -27
  82. package/dist/runtime/runtime.js +0 -77
  83. package/dist/runtime/runtime.js.map +0 -1
  84. package/dist/runtime/scheduler/index.d.ts +0 -22
  85. package/dist/runtime/scheduler/index.js +0 -20
  86. package/dist/runtime/scheduler/index.js.map +0 -1
  87. package/dist/runtime/server/applications.d.ts +0 -91
  88. package/dist/runtime/server/applications.js +0 -171
  89. package/dist/runtime/server/applications.js.map +0 -1
  90. package/dist/runtime/server/config.d.ts +0 -148
  91. package/dist/runtime/server/config.js +0 -33
  92. package/dist/runtime/server/config.js.map +0 -1
  93. package/dist/runtime/server/environment.d.ts +0 -43
  94. package/dist/runtime/server/environment.js +0 -33
  95. package/dist/runtime/server/environment.js.map +0 -1
  96. package/dist/runtime/server/error-policy.d.ts +0 -62
  97. package/dist/runtime/server/error-policy.js +0 -73
  98. package/dist/runtime/server/error-policy.js.map +0 -1
  99. package/dist/runtime/server/hmr-coordinator.d.ts +0 -37
  100. package/dist/runtime/server/hmr-coordinator.js +0 -94
  101. package/dist/runtime/server/hmr-coordinator.js.map +0 -1
  102. package/dist/runtime/server/jobs.d.ts +0 -54
  103. package/dist/runtime/server/jobs.js +0 -176
  104. package/dist/runtime/server/jobs.js.map +0 -1
  105. package/dist/runtime/server/lifecycle.d.ts +0 -85
  106. package/dist/runtime/server/lifecycle.js +0 -177
  107. package/dist/runtime/server/lifecycle.js.map +0 -1
  108. package/dist/runtime/server/managed-worker.d.ts +0 -158
  109. package/dist/runtime/server/managed-worker.js +0 -420
  110. package/dist/runtime/server/managed-worker.js.map +0 -1
  111. package/dist/runtime/server/pool-manager.d.ts +0 -85
  112. package/dist/runtime/server/pool-manager.js +0 -129
  113. package/dist/runtime/server/pool-manager.js.map +0 -1
  114. package/dist/runtime/server/proxy.d.ts +0 -21
  115. package/dist/runtime/server/proxy.js +0 -76
  116. package/dist/runtime/server/proxy.js.map +0 -1
  117. package/dist/runtime/server/server.d.ts +0 -60
  118. package/dist/runtime/server/server.js +0 -163
  119. package/dist/runtime/server/server.js.map +0 -1
  120. package/dist/runtime/server/types.d.ts +0 -31
  121. package/dist/runtime/server/types.js +0 -2
  122. package/dist/runtime/server/types.js.map +0 -1
  123. package/dist/runtime/server/worker-pool.d.ts +0 -121
  124. package/dist/runtime/server/worker-pool.js +0 -171
  125. package/dist/runtime/server/worker-pool.js.map +0 -1
  126. package/dist/runtime/store/index.d.ts +0 -3
  127. package/dist/runtime/store/index.js +0 -23
  128. package/dist/runtime/store/index.js.map +0 -1
  129. package/dist/runtime/subscription/manager.d.ts +0 -49
  130. package/dist/runtime/subscription/manager.js +0 -170
  131. package/dist/runtime/subscription/manager.js.map +0 -1
  132. package/dist/runtime/subscription/redis.d.ts +0 -18
  133. package/dist/runtime/subscription/redis.js +0 -119
  134. package/dist/runtime/subscription/redis.js.map +0 -1
  135. package/dist/runtime/types.d.ts +0 -95
  136. package/dist/runtime/types.js +0 -2
  137. package/dist/runtime/types.js.map +0 -1
  138. package/dist/runtime/workers/application.d.ts +0 -29
  139. package/dist/runtime/workers/application.js +0 -77
  140. package/dist/runtime/workers/application.js.map +0 -1
  141. package/dist/runtime/workers/base.d.ts +0 -14
  142. package/dist/runtime/workers/base.js +0 -41
  143. package/dist/runtime/workers/base.js.map +0 -1
  144. package/dist/runtime/workers/cli.d.ts +0 -1
  145. package/dist/runtime/workers/cli.js +0 -2
  146. package/dist/runtime/workers/cli.js.map +0 -1
  147. package/dist/runtime/workers/job.d.ts +0 -20
  148. package/dist/runtime/workers/job.js +0 -170
  149. package/dist/runtime/workers/job.js.map +0 -1
  150. package/dist/vite/builder.d.ts +0 -5
  151. package/dist/vite/builder.js +0 -79
  152. package/dist/vite/builder.js.map +0 -1
  153. package/dist/vite/config.d.ts +0 -28
  154. package/dist/vite/config.js +0 -22
  155. package/dist/vite/config.js.map +0 -1
  156. package/dist/vite/plugins.d.ts +0 -2
  157. package/dist/vite/plugins.js +0 -43
  158. package/dist/vite/plugins.js.map +0 -1
  159. package/dist/vite/runners/worker.d.ts +0 -3
  160. package/dist/vite/runners/worker.js +0 -34
  161. package/dist/vite/runners/worker.js.map +0 -1
  162. package/dist/vite/server.d.ts +0 -3
  163. package/dist/vite/server.js +0 -36
  164. package/dist/vite/server.js.map +0 -1
  165. package/dist/vite/servers/main.d.ts +0 -8
  166. package/dist/vite/servers/main.js +0 -24
  167. package/dist/vite/servers/main.js.map +0 -1
  168. package/dist/vite/servers/worker.d.ts +0 -13
  169. package/dist/vite/servers/worker.js +0 -124
  170. package/dist/vite/servers/worker.js.map +0 -1
  171. package/src/cli.ts +0 -162
  172. package/src/codegen.ts +0 -30
  173. package/src/config.ts +0 -69
  174. package/src/entrypoints/cli.ts +0 -13
  175. package/src/entrypoints/main.ts +0 -317
  176. package/src/entrypoints/thread.ts +0 -223
  177. package/src/entrypoints/worker.ts +0 -174
  178. package/src/resolver.ts +0 -7
  179. package/src/runtime/application/index.ts +0 -1
  180. package/src/runtime/constants.ts +0 -13
  181. package/src/runtime/enums.ts +0 -12
  182. package/src/runtime/hooks.ts +0 -1
  183. package/src/runtime/index.ts +0 -29
  184. package/src/runtime/injectables.ts +0 -101
  185. package/src/runtime/jobs/job.ts +0 -467
  186. package/src/runtime/jobs/manager.ts +0 -454
  187. package/src/runtime/jobs/router.ts +0 -967
  188. package/src/runtime/jobs/runner.ts +0 -583
  189. package/src/runtime/jobs/step.ts +0 -66
  190. package/src/runtime/jobs/types.ts +0 -116
  191. package/src/runtime/metrics/metric.ts +0 -18
  192. package/src/runtime/metrics/registry.ts +0 -11
  193. package/src/runtime/metrics/server.ts +0 -69
  194. package/src/runtime/plugin.ts +0 -2
  195. package/src/runtime/runtime.ts +0 -103
  196. package/src/runtime/scheduler/index.ts +0 -39
  197. package/src/runtime/server/applications.ts +0 -264
  198. package/src/runtime/server/config.ts +0 -199
  199. package/src/runtime/server/environment.ts +0 -71
  200. package/src/runtime/server/error-policy.ts +0 -132
  201. package/src/runtime/server/hmr-coordinator.ts +0 -116
  202. package/src/runtime/server/jobs.ts +0 -266
  203. package/src/runtime/server/lifecycle.ts +0 -234
  204. package/src/runtime/server/managed-worker.ts +0 -546
  205. package/src/runtime/server/pool-manager.ts +0 -187
  206. package/src/runtime/server/proxy.ts +0 -119
  207. package/src/runtime/server/server.ts +0 -218
  208. package/src/runtime/server/types.ts +0 -32
  209. package/src/runtime/server/worker-pool.ts +0 -275
  210. package/src/runtime/store/index.ts +0 -30
  211. package/src/runtime/subscription/manager.ts +0 -307
  212. package/src/runtime/subscription/redis.ts +0 -159
  213. package/src/runtime/types.ts +0 -84
  214. package/src/runtime/workers/application.ts +0 -133
  215. package/src/runtime/workers/base.ts +0 -65
  216. package/src/runtime/workers/cli.ts +0 -0
  217. package/src/runtime/workers/job.ts +0 -142
  218. package/src/vite/builder.ts +0 -94
  219. package/src/vite/config.ts +0 -45
  220. package/src/vite/plugins.ts +0 -53
  221. package/src/vite/runners/worker.ts +0 -55
  222. package/src/vite/server.ts +0 -55
  223. package/src/vite/servers/main.ts +0 -41
  224. package/src/vite/servers/worker.ts +0 -177
@@ -1,199 +0,0 @@
1
- import type {
2
- ApplicationHost,
3
- ApplicationHostDefinition,
4
- TransportOptionsOf,
5
- } from '@nmtjs/application'
6
- import type { LoggingOptions } from '@nmtjs/core'
7
- import type { ApplicationOptions } from '@nmtjs/proxy'
8
- import type { Applications } from 'nmtjs/runtime/types'
9
-
10
- import type { StoreType } from '../enums.ts'
11
- import type { AnyJob } from '../jobs/job.ts'
12
- import type { JobsSchedulerOptions } from '../scheduler/index.ts'
13
- import type { SubscriptionAdapterType } from '../subscription/manager.ts'
14
- import type { StoreTypeOptions } from '../types.ts'
15
- import { kServerConfig } from '../constants.ts'
16
-
17
- export type ServerPoolOptions = {
18
- /**
19
- * Number of worker threads
20
- */
21
- threads: number
22
- /**
23
- * Max number of jobs per worker
24
- */
25
- jobs: number
26
- }
27
-
28
- export type ServerStoreConfig =
29
- | { type: StoreType.Redis; options: StoreTypeOptions[StoreType.Redis] }
30
- | { type: StoreType.Valkey; options: StoreTypeOptions[StoreType.Valkey] }
31
-
32
- export type ServerApplicationConfig<T = ApplicationHostDefinition> =
33
- T extends ApplicationHostDefinition<any, infer Transports>
34
- ? {
35
- threads: {
36
- [K in keyof Transports]: TransportOptionsOf<Transports[K]>
37
- }[]
38
- }
39
- : T extends ApplicationHost<infer Transports>
40
- ? {
41
- threads: {
42
- [K in keyof Transports]: TransportOptionsOf<Transports[K]>
43
- }[]
44
- }
45
- : any
46
-
47
- export type ServerJobsConfig = {
48
- pools: Record<string, ServerPoolOptions>
49
- jobs?: AnyJob[]
50
- /**
51
- * @deprecated Scheduler is currently being refactored and is not available.
52
- * Using this option will throw an error at startup.
53
- */
54
- scheduler?: JobsSchedulerOptions
55
- }
56
-
57
- type ServerApplicationDefinitionConfig<T> = T extends {
58
- type: 'neemata'
59
- definition: infer Definition
60
- }
61
- ? ServerApplicationConfig<Definition>
62
- : ServerApplicationConfig<any>
63
-
64
- export interface ServerConfigInit {
65
- logger: LoggingOptions
66
- applications: {
67
- [K in keyof Applications]: ServerApplicationDefinitionConfig<
68
- Applications[K]
69
- >
70
- }
71
- store?: ServerStoreConfig
72
- /**
73
- * Proxy configuration. Enabling this will start a reverse proxy server that handles TLS, routing,
74
- * load balancing, and health checks for your applications.
75
- *
76
- * The applications will be accessible via `<hostname>:<port>/<application-name>/**`
77
- *
78
- * Requires adding `@nmtjs/proxy` package to your dependencies
79
- * and [`cargo`](https://doc.rust-lang.org/cargo/getting-started/installation.html) alongside with
80
- * [`rustc`](https://www.rust-lang.org/tools/install) to be available globally for building native modules.
81
- */
82
- proxy?: {
83
- port: number
84
- hostname: string
85
- applications: {
86
- [K in keyof Applications]?: Omit<ApplicationOptions, 'name'>
87
- }
88
- threads?: number
89
- healthChecks?: { interval?: number }
90
- tls?: { key: string; cert: string }
91
- }
92
- jobs?: ServerJobsConfig
93
- commands?: {}
94
- subscription?: { adapter: SubscriptionAdapterType }
95
- deploymentId?: string
96
- metrics?: {
97
- /**
98
- * @default '/metrics'
99
- */
100
- path?: string
101
- /**
102
- * @default 9187
103
- */
104
- port?: number
105
- /**
106
- * @default 0.0.0.0
107
- */
108
- host?: string
109
-
110
- push?: {
111
- /**
112
- * Pushgateway URL (including protocol and port)
113
- *
114
- * @default http://127.0.0.1:9091
115
- */
116
- url?: string
117
- /**
118
- * Job name for the pushgateway
119
- */
120
- name: string
121
- /**
122
- * Push interval in milliseconds
123
- */
124
- interval: number
125
- }
126
- }
127
- }
128
-
129
- export interface ServerConfig {
130
- [kServerConfig]: true
131
- logger: ServerConfigInit['logger']
132
- applications: ServerConfigInit['applications']
133
- store: ServerConfigInit['store']
134
- /**
135
- * Proxy configuration. Enabling this will start a reverse proxy server that handles TLS, routing,
136
- * load balancing, and health checks for your applications.
137
- *
138
- * The applications will be accessible via `<hostname>:<port>/<application-name>/**`
139
- *
140
- * Requires adding `@nmtjs/proxy` package to your dependencies
141
- */
142
- proxy: ServerConfigInit['proxy']
143
- jobs?: {
144
- pools: ServerJobsConfig['pools']
145
- jobs: Map<string, AnyJob>
146
- /**
147
- * @deprecated Scheduler is currently being refactored and is not available.
148
- * Using this option will throw an error at startup.
149
- */
150
- scheduler?: JobsSchedulerOptions
151
- }
152
- commands?: {}
153
- subscription: ServerConfigInit['subscription']
154
- deploymentId: ServerConfigInit['deploymentId']
155
- metrics?: ServerConfigInit['metrics']
156
- }
157
-
158
- export function defineServer(options: ServerConfigInit): ServerConfig {
159
- const {
160
- deploymentId,
161
- logger,
162
- commands,
163
- proxy,
164
- store,
165
- applications,
166
- subscription,
167
- metrics,
168
- } = options
169
-
170
- let jobs: ServerConfig['jobs'] | undefined
171
- if (options.jobs) {
172
- const map = new Map<string, AnyJob>()
173
- for (const job of options.jobs.jobs ?? []) map.set(job.name, job)
174
- for (const { job } of options.jobs.scheduler?.entries ?? [])
175
- map.set(job.name, job)
176
- jobs = {
177
- pools: options.jobs.pools,
178
- jobs: map,
179
- scheduler: options.jobs.scheduler,
180
- }
181
- }
182
-
183
- return Object.freeze({
184
- [kServerConfig]: true,
185
- deploymentId,
186
- logger,
187
- commands,
188
- proxy,
189
- store,
190
- applications,
191
- subscription,
192
- jobs,
193
- metrics,
194
- } as const)
195
- }
196
-
197
- export function isServerConfig(value: any): value is ServerConfig {
198
- return Boolean(value?.[kServerConfig])
199
- }
@@ -1,71 +0,0 @@
1
- import type { ViteDevServer } from 'vite'
2
-
3
- import type { ErrorPolicy } from './error-policy.ts'
4
- import type { HMRCoordinator } from './hmr-coordinator.ts'
5
- import { getErrorPolicy } from './error-policy.ts'
6
-
7
- /**
8
- * Encapsulates everything that differs between Dev and Prod environments.
9
- * This provides a clean abstraction over environment-specific behavior.
10
- */
11
- export interface RuntimeEnvironment {
12
- readonly mode: 'development' | 'production'
13
- readonly errorPolicy: ErrorPolicy
14
- readonly hmr: HMRCoordinator | null // null in prod
15
- readonly vite: ViteDevServer | null // null in prod
16
- }
17
-
18
- /**
19
- * Options for creating a development environment.
20
- */
21
- export interface DevEnvironmentOptions {
22
- vite?: ViteDevServer
23
- hmr?: HMRCoordinator
24
- }
25
-
26
- /**
27
- * Creates a RuntimeEnvironment for the given mode.
28
- *
29
- * @param mode - 'development' or 'production'
30
- * @param options - Optional configuration (vite server for dev mode)
31
- */
32
- export function createRuntimeEnvironment(
33
- mode: 'development' | 'production',
34
- options?: DevEnvironmentOptions,
35
- ): RuntimeEnvironment {
36
- const errorPolicy = getErrorPolicy(mode)
37
-
38
- if (mode === 'development') {
39
- return {
40
- mode,
41
- errorPolicy,
42
- hmr: options?.hmr ?? null,
43
- vite: options?.vite ?? null,
44
- }
45
- }
46
-
47
- // Production mode - no HMR or Vite
48
- return { mode, errorPolicy, hmr: null, vite: null }
49
- }
50
-
51
- /**
52
- * Type guard to check if environment is development mode.
53
- */
54
- export function isDevEnvironment(
55
- env: RuntimeEnvironment,
56
- ): env is RuntimeEnvironment & {
57
- mode: 'development'
58
- hmr: HMRCoordinator | null
59
- vite: ViteDevServer | null
60
- } {
61
- return env.mode === 'development'
62
- }
63
-
64
- /**
65
- * Type guard to check if environment is production mode.
66
- */
67
- export function isProdEnvironment(
68
- env: RuntimeEnvironment,
69
- ): env is RuntimeEnvironment & { mode: 'production'; hmr: null; vite: null } {
70
- return env.mode === 'production'
71
- }
@@ -1,132 +0,0 @@
1
- import type { WorkerType } from '../enums.ts'
2
-
3
- /**
4
- * Context provided to error policy decisions about worker failures.
5
- */
6
- export interface WorkerErrorContext {
7
- workerId: string
8
- workerType: WorkerType
9
- consecutiveFailures: number
10
- totalFailures: number
11
- lastStableTime: number | null
12
- }
13
-
14
- /**
15
- * Actions that can be taken in response to errors.
16
- */
17
- export type ErrorAction =
18
- | { type: 'exit'; code: number }
19
- | { type: 'restart'; delay: number }
20
- | { type: 'wait' } // Dev only: wait for HMR fix
21
- | { type: 'ignore' }
22
-
23
- /**
24
- * Interface defining error handling behavior for different environments.
25
- * Dev and Prod modes have different requirements and this interface makes those explicit.
26
- */
27
- export interface ErrorPolicy {
28
- /** How to handle server startup failure */
29
- onStartupError(error: Error): ErrorAction
30
-
31
- /** How to handle worker crash */
32
- onWorkerError(error: Error, context: WorkerErrorContext): ErrorAction
33
-
34
- /** Delay before restarting a failed worker */
35
- getRestartDelay(consecutiveFailures: number): number
36
-
37
- /** Whether to continue if some workers are down */
38
- readonly allowDegradedMode: boolean
39
- }
40
-
41
- /**
42
- * Calculates exponential backoff delay with a cap.
43
- * @param failures - Number of consecutive failures
44
- * @param base - Base delay in ms (default: 100)
45
- * @param maxDelay - Maximum delay in ms (default: 5000)
46
- */
47
- function exponentialBackoff(
48
- failures: number,
49
- base = 100,
50
- maxDelay = 5000,
51
- ): number {
52
- return Math.min(base * 2 ** Math.max(0, failures - 1), maxDelay)
53
- }
54
-
55
- /**
56
- * Time window in ms after which a worker is considered "stable".
57
- * If stable, consecutive failure count is reset on next error.
58
- */
59
- const STABILITY_WINDOW_MS = 30_000
60
-
61
- /**
62
- * Maximum retries before giving up in dev mode.
63
- */
64
- const DEV_MAX_RETRIES = 1
65
-
66
- /**
67
- * Maximum retries before exiting in prod mode.
68
- */
69
- const PROD_MAX_RETRIES = 3
70
-
71
- /**
72
- * Development Error Policy
73
- *
74
- * - Startup errors: Wait for HMR fix (don't exit)
75
- * - Worker errors: Restart with exponential backoff
76
- * - After 10 consecutive failures: Stop retrying, wait for HMR fix
77
- * - Stability window: Reset failure count if worker was stable for 30s+
78
- * - Degraded mode: Allowed (keep serving with partial workers)
79
- */
80
- export const DevErrorPolicy: ErrorPolicy = {
81
- onStartupError: () => ({ type: 'wait' }),
82
-
83
- onWorkerError: (_error, ctx) => {
84
- // Check if worker was stable before this failure
85
- const wasStable =
86
- ctx.lastStableTime !== null &&
87
- Date.now() - ctx.lastStableTime > STABILITY_WINDOW_MS
88
-
89
- // Reset failure count if was stable
90
- const effectiveFailures = wasStable ? 1 : ctx.consecutiveFailures
91
-
92
- if (effectiveFailures >= DEV_MAX_RETRIES) {
93
- return { type: 'wait' } // Stop trying, wait for HMR fix
94
- }
95
-
96
- return { type: 'restart', delay: exponentialBackoff(effectiveFailures) }
97
- },
98
-
99
- getRestartDelay: (n) => exponentialBackoff(n),
100
- allowDegradedMode: true,
101
- }
102
-
103
- /**
104
- * Production Error Policy
105
- *
106
- * - Startup errors: Exit immediately with code 1
107
- * - Worker errors: Restart up to 3 times, then exit
108
- * - No stability window consideration (each failure counts)
109
- * - Degraded mode: Not allowed (all workers must be healthy)
110
- */
111
- export const ProdErrorPolicy: ErrorPolicy = {
112
- onStartupError: () => ({ type: 'exit', code: 1 }),
113
-
114
- onWorkerError: (_error, ctx) => {
115
- if (ctx.consecutiveFailures >= PROD_MAX_RETRIES) {
116
- return { type: 'exit', code: 1 }
117
- }
118
- return { type: 'restart', delay: 1000 }
119
- },
120
-
121
- getRestartDelay: () => 1000,
122
- allowDegradedMode: false,
123
- }
124
-
125
- /**
126
- * Get the appropriate error policy for the given mode.
127
- */
128
- export function getErrorPolicy(
129
- mode: 'development' | 'production',
130
- ): ErrorPolicy {
131
- return mode === 'development' ? DevErrorPolicy : ProdErrorPolicy
132
- }
@@ -1,116 +0,0 @@
1
- import type { Logger } from '@nmtjs/core'
2
-
3
- import type { ServerLifecycle } from './lifecycle.ts'
4
-
5
- /**
6
- * HMRCoordinator handles HMR (Hot Module Replacement) with proper supersede logic.
7
- *
8
- * When a reload is in progress and another HMR event arrives, the pending reload
9
- * is superseded by the latest - only the most recent config is applied.
10
- *
11
- * This component is only used in development mode.
12
- */
13
- export class HMRCoordinator {
14
- /** Currently executing reload, if any */
15
- private active: Promise<void> | null = null
16
-
17
- /** Pending reload - only the latest request is kept */
18
- private pendingResolvers: {
19
- resolve: () => void
20
- reject: (e: Error) => void
21
- } | null = null
22
-
23
- /** Whether a reload is pending after the current one completes */
24
- private hasPending = false
25
-
26
- private logger: Logger
27
-
28
- constructor(
29
- private readonly lifecycle: ServerLifecycle,
30
- logger: Logger,
31
- ) {
32
- this.logger = logger.child({ component: 'HMRCoordinator' })
33
- }
34
-
35
- /**
36
- * Schedule a reload. If a reload is already in progress, supersedes any pending reload.
37
- *
38
- * @returns Promise that resolves when this reload completes (or is superseded)
39
- */
40
- async scheduleReload(): Promise<void> {
41
- // If no active reload, execute immediately
42
- if (!this.active) {
43
- return this.executeReload()
44
- }
45
-
46
- // Supersede any existing pending reload - resolve previous waiter
47
- if (this.pendingResolvers) {
48
- this.logger.debug('Superseding pending reload with new request')
49
- this.pendingResolvers.resolve()
50
- }
51
-
52
- // Mark that we have a pending reload
53
- this.hasPending = true
54
-
55
- // Create new pending promise for this caller
56
- return new Promise((resolve, reject) => {
57
- this.pendingResolvers = { resolve, reject }
58
- })
59
- }
60
-
61
- /**
62
- * Execute a reload, handling the pending queue.
63
- */
64
- private async executeReload(): Promise<void> {
65
- this.logger.debug('HMR reload starting')
66
-
67
- this.active = this.doReload()
68
-
69
- try {
70
- await this.active
71
- this.logger.debug('HMR reload complete')
72
- } finally {
73
- this.active = null
74
-
75
- // If there's a pending reload, execute it now
76
- if (this.hasPending && this.pendingResolvers) {
77
- const { resolve, reject } = this.pendingResolvers
78
- this.pendingResolvers = null
79
- this.hasPending = false
80
- this.executeReload().then(resolve, reject)
81
- }
82
- }
83
- }
84
-
85
- /**
86
- * Perform the actual reload via the lifecycle.
87
- */
88
- private async doReload(): Promise<void> {
89
- // Check if lifecycle can reload
90
- if (this.lifecycle.canReload) {
91
- await this.lifecycle.reload()
92
- } else if (this.lifecycle.canStart) {
93
- // If in failed/idle state, try to start
94
- await this.lifecycle.start()
95
- } else {
96
- this.logger.warn(
97
- { state: this.lifecycle.currentState },
98
- 'Cannot reload in current state',
99
- )
100
- }
101
- }
102
-
103
- /**
104
- * Check if a reload is currently in progress.
105
- */
106
- get isReloading(): boolean {
107
- return this.active !== null
108
- }
109
-
110
- /**
111
- * Check if there's a pending reload waiting.
112
- */
113
- get isPending(): boolean {
114
- return this.hasPending
115
- }
116
- }