@adonis-agora/durable 0.49.1 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/README.md +53 -22
  3. package/dist/assets/spa/assets/index-DupjrK7N.js +16 -0
  4. package/dist/assets/spa/assets/index-DupjrK7N.js.map +1 -0
  5. package/dist/assets/spa/index.html +1 -1
  6. package/dist/commands/durable_worker.d.ts.map +1 -1
  7. package/dist/commands/durable_worker.js +9 -8
  8. package/dist/commands/durable_worker.js.map +1 -1
  9. package/dist/commands/work.d.ts.map +1 -1
  10. package/dist/commands/work.js +3 -1
  11. package/dist/commands/work.js.map +1 -1
  12. package/dist/configure.d.ts.map +1 -1
  13. package/dist/configure.js +1 -0
  14. package/dist/configure.js.map +1 -1
  15. package/dist/providers/dashboard_provider.d.ts +2 -0
  16. package/dist/providers/dashboard_provider.d.ts.map +1 -1
  17. package/dist/providers/dashboard_provider.js +50 -6
  18. package/dist/providers/dashboard_provider.js.map +1 -1
  19. package/dist/providers/durable_provider.d.ts.map +1 -1
  20. package/dist/providers/durable_provider.js +146 -35
  21. package/dist/providers/durable_provider.js.map +1 -1
  22. package/dist/src/admission-redis/redis-admission-backend.d.ts.map +1 -1
  23. package/dist/src/admission-redis/redis-admission-backend.js +3 -1
  24. package/dist/src/admission-redis/redis-admission-backend.js.map +1 -1
  25. package/dist/src/ambient-step.d.ts +24 -0
  26. package/dist/src/ambient-step.d.ts.map +1 -0
  27. package/dist/src/ambient-step.js +42 -0
  28. package/dist/src/ambient-step.js.map +1 -0
  29. package/dist/src/base-workflow.d.ts +10 -1
  30. package/dist/src/base-workflow.d.ts.map +1 -1
  31. package/dist/src/base-workflow.js.map +1 -1
  32. package/dist/src/codec-state-store.d.ts +28 -2
  33. package/dist/src/codec-state-store.d.ts.map +1 -1
  34. package/dist/src/codec-state-store.js +61 -3
  35. package/dist/src/codec-state-store.js.map +1 -1
  36. package/dist/src/commands/worker.d.ts +8 -3
  37. package/dist/src/commands/worker.d.ts.map +1 -1
  38. package/dist/src/commands/worker.js +35 -8
  39. package/dist/src/commands/worker.js.map +1 -1
  40. package/dist/src/config_types.d.ts +6 -0
  41. package/dist/src/config_types.d.ts.map +1 -1
  42. package/dist/src/control-plane-redis/redis-control-plane.d.ts.map +1 -1
  43. package/dist/src/control-plane-redis/redis-control-plane.js +22 -6
  44. package/dist/src/control-plane-redis/redis-control-plane.js.map +1 -1
  45. package/dist/src/control-planes/factory.d.ts +6 -0
  46. package/dist/src/control-planes/factory.d.ts.map +1 -1
  47. package/dist/src/control-planes/factory.js +1 -0
  48. package/dist/src/control-planes/factory.js.map +1 -1
  49. package/dist/src/dashboard/gateway-adapter.d.ts +15 -5
  50. package/dist/src/dashboard/gateway-adapter.d.ts.map +1 -1
  51. package/dist/src/dashboard/gateway-adapter.js +71 -7
  52. package/dist/src/dashboard/gateway-adapter.js.map +1 -1
  53. package/dist/src/dashboard/handlers.d.ts +53 -1
  54. package/dist/src/dashboard/handlers.d.ts.map +1 -1
  55. package/dist/src/dashboard/handlers.js +200 -20
  56. package/dist/src/dashboard/handlers.js.map +1 -1
  57. package/dist/src/dashboard/index.d.ts +2 -2
  58. package/dist/src/dashboard/index.d.ts.map +1 -1
  59. package/dist/src/dashboard/index.js +2 -2
  60. package/dist/src/dashboard/index.js.map +1 -1
  61. package/dist/src/dashboard/openapi.d.ts.map +1 -1
  62. package/dist/src/dashboard/openapi.js +71 -1
  63. package/dist/src/dashboard/openapi.js.map +1 -1
  64. package/dist/src/define_config.d.ts +122 -8
  65. package/dist/src/define_config.d.ts.map +1 -1
  66. package/dist/src/define_config.js.map +1 -1
  67. package/dist/src/diagnostics-bridge.d.ts +16 -3
  68. package/dist/src/diagnostics-bridge.d.ts.map +1 -1
  69. package/dist/src/diagnostics-bridge.js +9 -3
  70. package/dist/src/diagnostics-bridge.js.map +1 -1
  71. package/dist/src/discovery-roots.d.ts +92 -0
  72. package/dist/src/discovery-roots.d.ts.map +1 -0
  73. package/dist/src/discovery-roots.js +150 -0
  74. package/dist/src/discovery-roots.js.map +1 -0
  75. package/dist/src/engine.d.ts +428 -21
  76. package/dist/src/engine.d.ts.map +1 -1
  77. package/dist/src/engine.js +1566 -164
  78. package/dist/src/engine.js.map +1 -1
  79. package/dist/src/entities.d.ts +36 -1
  80. package/dist/src/entities.d.ts.map +1 -1
  81. package/dist/src/entities.js +65 -4
  82. package/dist/src/entities.js.map +1 -1
  83. package/dist/src/errors.d.ts +46 -0
  84. package/dist/src/errors.d.ts.map +1 -1
  85. package/dist/src/errors.js +48 -0
  86. package/dist/src/errors.js.map +1 -1
  87. package/dist/src/event-trigger-bridge.d.ts +8 -0
  88. package/dist/src/event-trigger-bridge.d.ts.map +1 -1
  89. package/dist/src/event-trigger-bridge.js +24 -3
  90. package/dist/src/event-trigger-bridge.js.map +1 -1
  91. package/dist/src/handshake/announced.d.ts +27 -0
  92. package/dist/src/handshake/announced.d.ts.map +1 -1
  93. package/dist/src/handshake/announced.js +62 -0
  94. package/dist/src/handshake/announced.js.map +1 -1
  95. package/dist/src/handshake/directory.d.ts +92 -0
  96. package/dist/src/handshake/directory.d.ts.map +1 -0
  97. package/dist/src/handshake/directory.js +139 -0
  98. package/dist/src/handshake/directory.js.map +1 -0
  99. package/dist/src/hooks/barrel-sources.d.ts +28 -0
  100. package/dist/src/hooks/barrel-sources.d.ts.map +1 -0
  101. package/dist/src/hooks/barrel-sources.js +92 -0
  102. package/dist/src/hooks/barrel-sources.js.map +1 -0
  103. package/dist/src/hooks/steps.d.ts +12 -3
  104. package/dist/src/hooks/steps.d.ts.map +1 -1
  105. package/dist/src/hooks/steps.js +7 -11
  106. package/dist/src/hooks/steps.js.map +1 -1
  107. package/dist/src/hooks/workflows.d.ts +12 -3
  108. package/dist/src/hooks/workflows.d.ts.map +1 -1
  109. package/dist/src/hooks/workflows.js +7 -13
  110. package/dist/src/hooks/workflows.js.map +1 -1
  111. package/dist/src/index.d.ts +12 -3
  112. package/dist/src/index.d.ts.map +1 -1
  113. package/dist/src/index.js +12 -3
  114. package/dist/src/index.js.map +1 -1
  115. package/dist/src/interfaces.d.ts +309 -21
  116. package/dist/src/interfaces.d.ts.map +1 -1
  117. package/dist/src/interfaces.js +10 -0
  118. package/dist/src/interfaces.js.map +1 -1
  119. package/dist/src/metrics.d.ts.map +1 -1
  120. package/dist/src/metrics.js +5 -0
  121. package/dist/src/metrics.js.map +1 -1
  122. package/dist/src/namespaces.d.ts +17 -0
  123. package/dist/src/namespaces.d.ts.map +1 -0
  124. package/dist/src/namespaces.js +24 -0
  125. package/dist/src/namespaces.js.map +1 -0
  126. package/dist/src/on-error.d.ts +4 -1
  127. package/dist/src/on-error.d.ts.map +1 -1
  128. package/dist/src/on-error.js +15 -2
  129. package/dist/src/on-error.js.map +1 -1
  130. package/dist/src/otel/durable-metrics.d.ts.map +1 -1
  131. package/dist/src/otel/durable-metrics.js +5 -0
  132. package/dist/src/otel/durable-metrics.js.map +1 -1
  133. package/dist/src/otel/durable-otel.d.ts.map +1 -1
  134. package/dist/src/otel/durable-otel.js +5 -0
  135. package/dist/src/otel/durable-otel.js.map +1 -1
  136. package/dist/src/pollers.d.ts +10 -1
  137. package/dist/src/pollers.d.ts.map +1 -1
  138. package/dist/src/pollers.js +15 -5
  139. package/dist/src/pollers.js.map +1 -1
  140. package/dist/src/protocol.d.ts +12 -0
  141. package/dist/src/protocol.d.ts.map +1 -1
  142. package/dist/src/protocol.js +27 -1
  143. package/dist/src/protocol.js.map +1 -1
  144. package/dist/src/remote-event.d.ts +6 -0
  145. package/dist/src/remote-event.d.ts.map +1 -0
  146. package/dist/src/remote-event.js +19 -0
  147. package/dist/src/remote-event.js.map +1 -0
  148. package/dist/src/remote-workflow-executor.d.ts +34 -12
  149. package/dist/src/remote-workflow-executor.d.ts.map +1 -1
  150. package/dist/src/remote-workflow-executor.js +42 -40
  151. package/dist/src/remote-workflow-executor.js.map +1 -1
  152. package/dist/src/run-detail-summary.d.ts +90 -3
  153. package/dist/src/run-detail-summary.d.ts.map +1 -1
  154. package/dist/src/run-detail-summary.js +360 -2
  155. package/dist/src/run-detail-summary.js.map +1 -1
  156. package/dist/src/run-facets.d.ts +48 -0
  157. package/dist/src/run-facets.d.ts.map +1 -0
  158. package/dist/src/run-facets.js +100 -0
  159. package/dist/src/run-facets.js.map +1 -0
  160. package/dist/src/run-gateway/interface.d.ts +27 -1
  161. package/dist/src/run-gateway/interface.d.ts.map +1 -1
  162. package/dist/src/run-gateway/proxy-run-gateway.d.ts +32 -4
  163. package/dist/src/run-gateway/proxy-run-gateway.d.ts.map +1 -1
  164. package/dist/src/run-gateway/proxy-run-gateway.js +101 -5
  165. package/dist/src/run-gateway/proxy-run-gateway.js.map +1 -1
  166. package/dist/src/run-gateway/run-request-responder.d.ts +18 -5
  167. package/dist/src/run-gateway/run-request-responder.d.ts.map +1 -1
  168. package/dist/src/run-gateway/run-request-responder.js +155 -32
  169. package/dist/src/run-gateway/run-request-responder.js.map +1 -1
  170. package/dist/src/run-gateway/store-run-gateway.d.ts +23 -1
  171. package/dist/src/run-gateway/store-run-gateway.d.ts.map +1 -1
  172. package/dist/src/run-gateway/store-run-gateway.js +38 -0
  173. package/dist/src/run-gateway/store-run-gateway.js.map +1 -1
  174. package/dist/src/scheduler.d.ts +44 -3
  175. package/dist/src/scheduler.d.ts.map +1 -1
  176. package/dist/src/scheduler.js +36 -1
  177. package/dist/src/scheduler.js.map +1 -1
  178. package/dist/src/search-attributes-schema.d.ts +44 -0
  179. package/dist/src/search-attributes-schema.d.ts.map +1 -0
  180. package/dist/src/search-attributes-schema.js +51 -0
  181. package/dist/src/search-attributes-schema.js.map +1 -0
  182. package/dist/src/singleton-admission.d.ts +75 -0
  183. package/dist/src/singleton-admission.d.ts.map +1 -0
  184. package/dist/src/singleton-admission.js +156 -0
  185. package/dist/src/singleton-admission.js.map +1 -0
  186. package/dist/src/singleton-gate.d.ts +23 -8
  187. package/dist/src/singleton-gate.d.ts.map +1 -1
  188. package/dist/src/singleton-gate.js +59 -12
  189. package/dist/src/singleton-gate.js.map +1 -1
  190. package/dist/src/standard-schema.d.ts +86 -0
  191. package/dist/src/standard-schema.d.ts.map +1 -0
  192. package/dist/src/standard-schema.js +33 -0
  193. package/dist/src/standard-schema.js.map +1 -0
  194. package/dist/src/step-discovery.d.ts +21 -11
  195. package/dist/src/step-discovery.d.ts.map +1 -1
  196. package/dist/src/step-discovery.js +86 -45
  197. package/dist/src/step-discovery.js.map +1 -1
  198. package/dist/src/step-ref.d.ts +38 -12
  199. package/dist/src/step-ref.d.ts.map +1 -1
  200. package/dist/src/step-ref.js +5 -13
  201. package/dist/src/step-ref.js.map +1 -1
  202. package/dist/src/stores/factory.d.ts +6 -0
  203. package/dist/src/stores/factory.d.ts.map +1 -1
  204. package/dist/src/stores/factory.js +4 -1
  205. package/dist/src/stores/factory.js.map +1 -1
  206. package/dist/src/stores/lucid-helpers.d.ts +2 -0
  207. package/dist/src/stores/lucid-helpers.d.ts.map +1 -1
  208. package/dist/src/stores/lucid-helpers.js +7 -0
  209. package/dist/src/stores/lucid-helpers.js.map +1 -1
  210. package/dist/src/stores/lucid-mappers.d.ts +25 -0
  211. package/dist/src/stores/lucid-mappers.d.ts.map +1 -1
  212. package/dist/src/stores/lucid-mappers.js +81 -18
  213. package/dist/src/stores/lucid-mappers.js.map +1 -1
  214. package/dist/src/stores/lucid-schema.d.ts +59 -1
  215. package/dist/src/stores/lucid-schema.d.ts.map +1 -1
  216. package/dist/src/stores/lucid-schema.js +271 -25
  217. package/dist/src/stores/lucid-schema.js.map +1 -1
  218. package/dist/src/stores/lucid.d.ts +61 -2
  219. package/dist/src/stores/lucid.d.ts.map +1 -1
  220. package/dist/src/stores/lucid.js +346 -41
  221. package/dist/src/stores/lucid.js.map +1 -1
  222. package/dist/src/telescope/dashboard.d.ts.map +1 -1
  223. package/dist/src/telescope/dashboard.js +30 -1
  224. package/dist/src/telescope/dashboard.js.map +1 -1
  225. package/dist/src/telescope/data-providers.d.ts +19 -1
  226. package/dist/src/telescope/data-providers.d.ts.map +1 -1
  227. package/dist/src/telescope/data-providers.js +119 -3
  228. package/dist/src/telescope/data-providers.js.map +1 -1
  229. package/dist/src/telescope/extension.d.ts.map +1 -1
  230. package/dist/src/telescope/extension.js +2 -1
  231. package/dist/src/telescope/extension.js.map +1 -1
  232. package/dist/src/telescope/index.d.ts +1 -1
  233. package/dist/src/telescope/index.d.ts.map +1 -1
  234. package/dist/src/telescope/index.js +1 -1
  235. package/dist/src/telescope/index.js.map +1 -1
  236. package/dist/src/testing/in-memory-state-store.d.ts +44 -15
  237. package/dist/src/testing/in-memory-state-store.d.ts.map +1 -1
  238. package/dist/src/testing/in-memory-state-store.js +204 -41
  239. package/dist/src/testing/in-memory-state-store.js.map +1 -1
  240. package/dist/src/testing-kit/checkpoint-aggregation-contract.d.ts +16 -0
  241. package/dist/src/testing-kit/checkpoint-aggregation-contract.d.ts.map +1 -0
  242. package/dist/src/testing-kit/checkpoint-aggregation-contract.js +228 -0
  243. package/dist/src/testing-kit/checkpoint-aggregation-contract.js.map +1 -0
  244. package/dist/src/testing-kit/state-store-conformance.d.ts.map +1 -1
  245. package/dist/src/testing-kit/state-store-conformance.js +355 -3
  246. package/dist/src/testing-kit/state-store-conformance.js.map +1 -1
  247. package/dist/src/transport-pool.d.ts +15 -1
  248. package/dist/src/transport-pool.d.ts.map +1 -1
  249. package/dist/src/transport-pool.js +50 -4
  250. package/dist/src/transport-pool.js.map +1 -1
  251. package/dist/src/transports/adaptive-concurrency.d.ts +168 -0
  252. package/dist/src/transports/adaptive-concurrency.d.ts.map +1 -0
  253. package/dist/src/transports/adaptive-concurrency.js +353 -0
  254. package/dist/src/transports/adaptive-concurrency.js.map +1 -0
  255. package/dist/src/transports/bullmq/adaptive-concurrency.d.ts +1 -165
  256. package/dist/src/transports/bullmq/adaptive-concurrency.d.ts.map +1 -1
  257. package/dist/src/transports/bullmq/adaptive-concurrency.js +3 -351
  258. package/dist/src/transports/bullmq/adaptive-concurrency.js.map +1 -1
  259. package/dist/src/transports/bullmq/bullmq-transport.d.ts +49 -1
  260. package/dist/src/transports/bullmq/bullmq-transport.d.ts.map +1 -1
  261. package/dist/src/transports/bullmq/bullmq-transport.js +330 -38
  262. package/dist/src/transports/bullmq/bullmq-transport.js.map +1 -1
  263. package/dist/src/transports/bullmq/deps.d.ts +18 -2
  264. package/dist/src/transports/bullmq/deps.d.ts.map +1 -1
  265. package/dist/src/transports/bullmq/deps.js +44 -2
  266. package/dist/src/transports/bullmq/deps.js.map +1 -1
  267. package/dist/src/transports/db-helpers.d.ts +39 -0
  268. package/dist/src/transports/db-helpers.d.ts.map +1 -1
  269. package/dist/src/transports/db-helpers.js +73 -0
  270. package/dist/src/transports/db-helpers.js.map +1 -1
  271. package/dist/src/transports/db-remote.d.ts +53 -0
  272. package/dist/src/transports/db-remote.d.ts.map +1 -0
  273. package/dist/src/transports/db-remote.js +147 -0
  274. package/dist/src/transports/db-remote.js.map +1 -0
  275. package/dist/src/transports/db-schema.d.ts +44 -1
  276. package/dist/src/transports/db-schema.d.ts.map +1 -1
  277. package/dist/src/transports/db-schema.js +227 -88
  278. package/dist/src/transports/db-schema.js.map +1 -1
  279. package/dist/src/transports/db.d.ts +189 -6
  280. package/dist/src/transports/db.d.ts.map +1 -1
  281. package/dist/src/transports/db.js +1291 -137
  282. package/dist/src/transports/db.js.map +1 -1
  283. package/dist/src/transports/event-emitter.d.ts +8 -0
  284. package/dist/src/transports/event-emitter.d.ts.map +1 -1
  285. package/dist/src/transports/event-emitter.js +36 -3
  286. package/dist/src/transports/event-emitter.js.map +1 -1
  287. package/dist/src/transports/factory.d.ts +110 -5
  288. package/dist/src/transports/factory.d.ts.map +1 -1
  289. package/dist/src/transports/factory.js +56 -9
  290. package/dist/src/transports/factory.js.map +1 -1
  291. package/dist/src/transports/queue-mock-adapter.d.ts +7 -2
  292. package/dist/src/transports/queue-mock-adapter.d.ts.map +1 -1
  293. package/dist/src/transports/queue-mock-adapter.js +18 -2
  294. package/dist/src/transports/queue-mock-adapter.js.map +1 -1
  295. package/dist/src/transports/queue-remote.d.ts +146 -0
  296. package/dist/src/transports/queue-remote.d.ts.map +1 -0
  297. package/dist/src/transports/queue-remote.js +398 -0
  298. package/dist/src/transports/queue-remote.js.map +1 -0
  299. package/dist/src/transports/queue.d.ts +159 -6
  300. package/dist/src/transports/queue.d.ts.map +1 -1
  301. package/dist/src/transports/queue.js +747 -37
  302. package/dist/src/transports/queue.js.map +1 -1
  303. package/dist/src/transports/task-failure.d.ts +31 -0
  304. package/dist/src/transports/task-failure.d.ts.map +1 -0
  305. package/dist/src/transports/task-failure.js +50 -0
  306. package/dist/src/transports/task-failure.js.map +1 -0
  307. package/dist/src/workflow-als.d.ts +1 -1
  308. package/dist/src/workflow-als.d.ts.map +1 -1
  309. package/dist/src/workflow-ctx.d.ts +10 -0
  310. package/dist/src/workflow-ctx.d.ts.map +1 -1
  311. package/dist/src/workflow-ctx.js +97 -15
  312. package/dist/src/workflow-ctx.js.map +1 -1
  313. package/dist/src/workflow-discovery.d.ts +32 -41
  314. package/dist/src/workflow-discovery.d.ts.map +1 -1
  315. package/dist/src/workflow-discovery.js +65 -88
  316. package/dist/src/workflow-discovery.js.map +1 -1
  317. package/dist/src/workflow-ref.d.ts +26 -0
  318. package/dist/src/workflow-ref.d.ts.map +1 -1
  319. package/dist/src/workflow-ref.js.map +1 -1
  320. package/dist/stubs/config/durable.stub +6 -0
  321. package/dist/stubs/config/durable_dashboard.stub +7 -3
  322. package/dist/stubs/database/migrations/create_durable_tables.stub +2 -1
  323. package/dist/stubs/database/migrations/create_durable_transport_messages.stub +43 -0
  324. package/dist/stubs/database/migrations/create_durable_transport_tables.stub +12 -9
  325. package/dist/stubs/database/migrations/create_durable_transport_worker_keys.stub +1 -1
  326. package/dist/stubs/make/workflow/main.stub +1 -1
  327. package/package.json +6 -4
  328. package/skills/durable-cluster/SKILL.md +80 -11
  329. package/skills/durable-determinism/SKILL.md +11 -5
  330. package/skills/durable-reliability/SKILL.md +77 -37
  331. package/skills/durable-setup/SKILL.md +51 -22
  332. package/skills/durable-transports-stores/SKILL.md +128 -18
  333. package/skills/durable-workflows/SKILL.md +83 -18
  334. package/dist/assets/spa/assets/index-DdB9zxuX.js +0 -16
  335. package/dist/assets/spa/assets/index-DdB9zxuX.js.map +0 -1
@@ -0,0 +1,168 @@
1
+ import type { WorkerStatus } from '../interfaces.js';
2
+ /**
3
+ * The adaptive controller's tunables — every field optional, each with a default from the spec.
4
+ * Spread under `{ mode: 'adaptive' }` to widen a plain `concurrency: number` into a self-tuning knob.
5
+ */
6
+ export interface AdaptiveConcurrencyOptions {
7
+ /** Floor the controller won't go below. Default 1. */
8
+ min?: number;
9
+ /** Ceiling the controller won't exceed. Default 32. */
10
+ max?: number;
11
+ /** Initial limit. Default `min` (clamped into `[min,max]`). */
12
+ start?: number;
13
+ /** RSS percent of the memory ceiling at which the hard brake fires. Default 85. */
14
+ ramCeilingPct?: number;
15
+ /** CPU percent (0..100×cores normalised to 0..100) ceiling; absent = off. Default undefined. */
16
+ cpuCeilingPct?: number;
17
+ /** Control-loop period in ms. Default 2000. */
18
+ tickMs?: number;
19
+ }
20
+ /**
21
+ * The `concurrency` option, widened (backward-compatible): a plain `number` is fixed (unchanged), the
22
+ * string `'adaptive'` is adaptive-with-defaults, and an object `{ mode:'adaptive', ... }` is adaptive
23
+ * with overrides. `undefined` keeps the historical default of 1 (fixed).
24
+ */
25
+ export type ConcurrencyOption = number | 'adaptive' | ({
26
+ mode: 'adaptive';
27
+ } & AdaptiveConcurrencyOptions);
28
+ /** The fully-resolved adaptive tunables (every default applied), carried on a resolved config. */
29
+ export interface AdaptiveConfig {
30
+ min: number;
31
+ max: number;
32
+ start: number;
33
+ ramCeilingPct: number;
34
+ cpuCeilingPct?: number;
35
+ tickMs: number;
36
+ }
37
+ /** A normalised `concurrency` option: a `fixed` number, or an `adaptive` config with every default applied. */
38
+ export interface ResolvedConcurrency {
39
+ mode: 'fixed' | 'adaptive';
40
+ /** Present when `mode === 'fixed'` — the never-moving concurrency. */
41
+ fixed?: number;
42
+ /** Present when `mode === 'adaptive'` — the controller's tunables. */
43
+ adaptive?: AdaptiveConfig;
44
+ }
45
+ /**
46
+ * Normalise a {@link ConcurrencyOption} into a {@link ResolvedConcurrency}: a bare number (or
47
+ * `undefined` → 1) becomes `{ mode:'fixed', fixed }`; `'adaptive'` / `{ mode:'adaptive', ... }`
48
+ * become `{ mode:'adaptive', adaptive }` with every default from the spec applied and `start`
49
+ * clamped into `[min,max]`.
50
+ *
51
+ * A non-finite or out-of-range number falls back to its default (a bad `cpuCeilingPct` turns the
52
+ * CPU ceiling off): BullMQ throws on a `NaN` or sub-1 concurrency, a `NaN` ceiling never brakes, and
53
+ * a `NaN` `tickMs` makes the control loop fire every millisecond.
54
+ */
55
+ export declare function resolveConcurrency(opt?: ConcurrencyOption): ResolvedConcurrency;
56
+ /**
57
+ * The process memory ceiling in bytes, read once (cgroup limits don't move at runtime): cgroup v2
58
+ * `memory.max`, then cgroup v1 `memory.limit_in_bytes`, then the host total. A `max` / absurdly-large
59
+ * ("unlimited") cgroup value falls through to {@link totalmem}. No new deps — just `node:fs`/`node:os`.
60
+ */
61
+ export declare function readMemoryLimitBytes(): number;
62
+ /** Construction surface for {@link AdaptiveController}. */
63
+ export interface AdaptiveControllerOptions {
64
+ /** The raw `concurrency` option (resolved internally). */
65
+ concurrency?: ConcurrencyOption;
66
+ /**
67
+ * Applied whenever the live limit changes — BullMQ wires it to `worker.concurrency = limit`, the
68
+ * queue transport to waking its slot loops. Called once with the initial limit is NOT done here; the
69
+ * caller starts at {@link AdaptiveController.initialLimit} and reads {@link AdaptiveController.limit}.
70
+ * Subsequent adaptive moves call this.
71
+ */
72
+ apply?: (limit: number) => void;
73
+ /** Injectable clock (tests). Defaults to {@link Date.now}. */
74
+ now?: () => number;
75
+ /** Injectable RSS reader (tests). Defaults to `process.memoryUsage().rss`. */
76
+ readRss?: () => number;
77
+ /** Injectable memory-ceiling reader (tests). Defaults to {@link readMemoryLimitBytes} (read once). */
78
+ readMemoryLimit?: () => number;
79
+ /** Injectable cumulative CPU-time reader (tests). Defaults to `process.cpuUsage()`. */
80
+ readCpuUsage?: () => NodeJS.CpuUsage;
81
+ /** Injectable core-count reader (tests), read once. Defaults to `os.cpus().length`. */
82
+ readCpuCount?: () => number;
83
+ }
84
+ /**
85
+ * A single gradient-limit (AIMD) concurrency controller, shared by every per-routing-token task
86
+ * worker of one transport ({@link import('./bullmq/bullmq-transport.js').BullMQTransport} or
87
+ * {@link import('./queue.js').QueueTransport}). It tracks in-flight work and a rolling window of
88
+ * completions, and — in `adaptive` mode — re-evaluates the worker's concurrency every `tickMs` from a
89
+ * latency gradient, an error/stall backpressure signal, a hard RAM brake and an optional CPU ceiling.
90
+ *
91
+ * In `fixed` mode no control loop runs and the limit never moves, but the controller still tracks
92
+ * `inFlight`/RSS/throughput/p95 (and samples CPU when a snapshot is taken) so the observability half
93
+ * (the heartbeat status payload) works without adaptive. Either way, {@link snapshot} returns the
94
+ * shared {@link WorkerStatus} contract the heartbeat writer stamps.
95
+ */
96
+ export declare class AdaptiveController {
97
+ private readonly resolved;
98
+ private readonly apply;
99
+ private readonly now;
100
+ private readonly readRss;
101
+ private readonly memoryLimitBytes;
102
+ private readonly tickMs;
103
+ private readonly readCpuUsage;
104
+ private readonly cpuCores;
105
+ private currentLimit;
106
+ private inFlightCount;
107
+ private readonly window;
108
+ private rttLongMs?;
109
+ private cpuPct?;
110
+ private lastAdjust?;
111
+ private completionsThisTick;
112
+ private stallTicks;
113
+ private lastCpuUsage?;
114
+ private lastCpuSampleAt;
115
+ private timer;
116
+ constructor(options?: AdaptiveControllerOptions);
117
+ /** The concurrency a task consumer starts at (fixed N, or the adaptive `start`). */
118
+ get initialLimit(): number;
119
+ /** The live limit in effect right now. */
120
+ get limit(): number;
121
+ /** `true` when the controller will move the limit on its own (adaptive mode). */
122
+ get isAdaptive(): boolean;
123
+ /**
124
+ * Start the control loop (adaptive mode only; fixed mode just takes a CPU baseline). The timer is
125
+ * `unref`'d so it never keeps the process alive; idempotent.
126
+ */
127
+ start(): void;
128
+ /** Stop the control loop (call on worker close). Idempotent. */
129
+ stop(): void;
130
+ /** A task started — bump in-flight. Call from the job processor before awaiting the body. */
131
+ onStart(): void;
132
+ /**
133
+ * A task settled. ALWAYS drops in-flight and counts toward stall liveness (`completionsThisTick`),
134
+ * so the saturation gate, the heartbeat `inFlight`, and the "alive-but-busy" signal see every task.
135
+ *
136
+ * `kind` gates the MEASUREMENT window: only `'step'` completions push a duration into the rolling
137
+ * window that feeds the latency gradient / throughput / p95 / error rate. A workflow TURN
138
+ * (`kind: 'workflow'`) is NOT measured — a 5ms suspend sitting next to a 2s step would corrupt the
139
+ * gradient — but it still counts as in-flight + forward progress. This is the single concurrency
140
+ * pool measuring steps only; the transport tags the kind when it routes a job by shape.
141
+ */
142
+ onSettle(durationMs: number, ok: boolean, kind: 'workflow' | 'step'): void;
143
+ /**
144
+ * One control-loop iteration: sample CPU, refresh the latency baseline, then decide the next limit
145
+ * and apply it. A no-op in fixed mode. Exposed (not private) so a test can drive ticks
146
+ * deterministically.
147
+ */
148
+ tick(): void;
149
+ private resetCpuBaseline;
150
+ /** Set `cpuPct` from the CPU time spent since the previous sample, over `elapsedMs` of wall time. */
151
+ private sampleCpu;
152
+ /** Fixed mode has no control loop, so a snapshot samples CPU itself, at most once per tick period
153
+ * (several heartbeat keys snapshot back to back, and a near-zero span gives a meaningless rate). */
154
+ private sampleCpuForSnapshot;
155
+ private refreshRttLong;
156
+ private rssPct;
157
+ private decide;
158
+ /** The shared {@link WorkerStatus} the heartbeat writer stamps. Best-effort fields are omitted when
159
+ * unmeasured (no completions yet → no p95/throughput; no CPU sample yet → no `cpuPct`). */
160
+ snapshot(): WorkerStatus;
161
+ /**
162
+ * Completions per minute over the trailing minute: the window's completions from the last minute,
163
+ * over the span from the oldest of them (or a full minute, when the window reaches further back) to
164
+ * now, floored at a second. The rate decays while the worker is idle and reads 0 once a minute passes with no completion.
165
+ */
166
+ private throughputPerMin;
167
+ }
168
+ //# sourceMappingURL=adaptive-concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-concurrency.d.ts","sourceRoot":"","sources":["../../../src/transports/adaptive-concurrency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,353 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { cpus, totalmem } from 'node:os';
3
+ const DEFAULT_MIN = 1;
4
+ const DEFAULT_MAX = 32;
5
+ const DEFAULT_RAM_CEILING_PCT = 85;
6
+ const DEFAULT_TICK_MS = 2000;
7
+ function clamp(value, min, max) {
8
+ return Math.min(max, Math.max(min, value));
9
+ }
10
+ /** `value` floored when it is a finite number of at least 1, else `fallback`. */
11
+ function wholeAtLeastOne(value, fallback) {
12
+ return value !== undefined && Number.isFinite(value) && value >= 1 ? Math.floor(value) : fallback;
13
+ }
14
+ /** `value` when it is a finite number above 0, else `fallback`. */
15
+ function finitePositive(value, fallback) {
16
+ return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;
17
+ }
18
+ /**
19
+ * Normalise a {@link ConcurrencyOption} into a {@link ResolvedConcurrency}: a bare number (or
20
+ * `undefined` → 1) becomes `{ mode:'fixed', fixed }`; `'adaptive'` / `{ mode:'adaptive', ... }`
21
+ * become `{ mode:'adaptive', adaptive }` with every default from the spec applied and `start`
22
+ * clamped into `[min,max]`.
23
+ *
24
+ * A non-finite or out-of-range number falls back to its default (a bad `cpuCeilingPct` turns the
25
+ * CPU ceiling off): BullMQ throws on a `NaN` or sub-1 concurrency, a `NaN` ceiling never brakes, and
26
+ * a `NaN` `tickMs` makes the control loop fire every millisecond.
27
+ */
28
+ export function resolveConcurrency(opt) {
29
+ if (opt === undefined)
30
+ return { mode: 'fixed', fixed: 1 };
31
+ if (typeof opt === 'number')
32
+ return { mode: 'fixed', fixed: wholeAtLeastOne(opt, 1) };
33
+ const overrides = opt === 'adaptive' ? {} : opt;
34
+ const min = wholeAtLeastOne(overrides.min, DEFAULT_MIN);
35
+ const max = Math.max(min, wholeAtLeastOne(overrides.max, DEFAULT_MAX));
36
+ const start = clamp(wholeAtLeastOne(overrides.start, min), min, max);
37
+ const cpuCeilingPct = finitePositive(overrides.cpuCeilingPct, undefined);
38
+ const adaptive = {
39
+ min,
40
+ max,
41
+ start,
42
+ ramCeilingPct: finitePositive(overrides.ramCeilingPct, DEFAULT_RAM_CEILING_PCT),
43
+ tickMs: wholeAtLeastOne(overrides.tickMs, DEFAULT_TICK_MS),
44
+ ...(cpuCeilingPct !== undefined ? { cpuCeilingPct } : {}),
45
+ };
46
+ return { mode: 'adaptive', adaptive };
47
+ }
48
+ // The cgroup "unlimited" sentinel: a limit at/above this is no real cap, so fall through to host total.
49
+ const CGROUP_UNLIMITED = 2 ** 62;
50
+ /**
51
+ * The process memory ceiling in bytes, read once (cgroup limits don't move at runtime): cgroup v2
52
+ * `memory.max`, then cgroup v1 `memory.limit_in_bytes`, then the host total. A `max` / absurdly-large
53
+ * ("unlimited") cgroup value falls through to {@link totalmem}. No new deps — just `node:fs`/`node:os`.
54
+ */
55
+ export function readMemoryLimitBytes() {
56
+ try {
57
+ const raw = readFileSync('/sys/fs/cgroup/memory.max', 'utf8').trim();
58
+ if (raw && raw !== 'max') {
59
+ const n = Number(raw);
60
+ if (Number.isFinite(n) && n > 0 && n < CGROUP_UNLIMITED)
61
+ return n;
62
+ }
63
+ }
64
+ catch {
65
+ /* not cgroup v2 (or unreadable) — try v1 next */
66
+ }
67
+ try {
68
+ const raw = readFileSync('/sys/fs/cgroup/memory/memory.limit_in_bytes', 'utf8').trim();
69
+ const n = Number(raw);
70
+ if (Number.isFinite(n) && n > 0 && n < CGROUP_UNLIMITED)
71
+ return n;
72
+ }
73
+ catch {
74
+ /* not cgroup v1 (or unreadable) — fall through to host total */
75
+ }
76
+ return totalmem();
77
+ }
78
+ // How many recent completions the controller reasons over (latency percentiles + throughput + errors).
79
+ const WINDOW_SIZE = 100;
80
+ // EWMA smoothing for the "no-queuing" baseline (rttLong): low weight so a single fast sample doesn't
81
+ // reset the baseline, but it still tracks a genuine floor shift.
82
+ const RTT_LONG_EWMA_ALPHA = 0.2;
83
+ // Consecutive ticks with in-flight work but zero completions before we call the worker stalled.
84
+ const STALL_TICKS = 2;
85
+ // Throughput is a rate over the trailing minute: a window whose newest completion is older than this
86
+ // reports 0, so an idle worker never advertises its last burst as live.
87
+ const THROUGHPUT_WINDOW_MS = 60_000;
88
+ // The shortest span a rate is computed over, so a worker's first completion doesn't extrapolate a
89
+ // sub-millisecond gap into a huge per-minute figure.
90
+ const THROUGHPUT_MIN_SPAN_MS = 1_000;
91
+ function percentile(sortedAsc, p) {
92
+ if (sortedAsc.length === 0)
93
+ return 0;
94
+ const idx = clamp(Math.ceil((p / 100) * sortedAsc.length) - 1, 0, sortedAsc.length - 1);
95
+ return sortedAsc[idx] ?? 0;
96
+ }
97
+ /**
98
+ * A single gradient-limit (AIMD) concurrency controller, shared by every per-routing-token task
99
+ * worker of one transport ({@link import('./bullmq/bullmq-transport.js').BullMQTransport} or
100
+ * {@link import('./queue.js').QueueTransport}). It tracks in-flight work and a rolling window of
101
+ * completions, and — in `adaptive` mode — re-evaluates the worker's concurrency every `tickMs` from a
102
+ * latency gradient, an error/stall backpressure signal, a hard RAM brake and an optional CPU ceiling.
103
+ *
104
+ * In `fixed` mode no control loop runs and the limit never moves, but the controller still tracks
105
+ * `inFlight`/RSS/throughput/p95 (and samples CPU when a snapshot is taken) so the observability half
106
+ * (the heartbeat status payload) works without adaptive. Either way, {@link snapshot} returns the
107
+ * shared {@link WorkerStatus} contract the heartbeat writer stamps.
108
+ */
109
+ export class AdaptiveController {
110
+ resolved;
111
+ apply;
112
+ now;
113
+ readRss;
114
+ memoryLimitBytes;
115
+ tickMs;
116
+ readCpuUsage;
117
+ cpuCores;
118
+ currentLimit;
119
+ inFlightCount = 0;
120
+ window = [];
121
+ rttLongMs;
122
+ cpuPct;
123
+ lastAdjust;
124
+ completionsThisTick = 0;
125
+ stallTicks = 0;
126
+ lastCpuUsage;
127
+ lastCpuSampleAt = 0;
128
+ timer;
129
+ constructor(options = {}) {
130
+ this.resolved = resolveConcurrency(options.concurrency);
131
+ this.apply = options.apply ?? (() => { });
132
+ this.now = options.now ?? Date.now;
133
+ this.readRss = options.readRss ?? (() => process.memoryUsage().rss);
134
+ this.memoryLimitBytes = (options.readMemoryLimit ?? readMemoryLimitBytes)();
135
+ this.tickMs = this.resolved.adaptive?.tickMs ?? DEFAULT_TICK_MS;
136
+ this.readCpuUsage = options.readCpuUsage ?? (() => process.cpuUsage());
137
+ this.cpuCores = wholeAtLeastOne((options.readCpuCount ?? (() => cpus().length))(), 1);
138
+ this.currentLimit =
139
+ this.resolved.mode === 'adaptive'
140
+ ? (this.resolved.adaptive?.start ?? DEFAULT_MIN)
141
+ : (this.resolved.fixed ?? 1);
142
+ }
143
+ /** The concurrency a task consumer starts at (fixed N, or the adaptive `start`). */
144
+ get initialLimit() {
145
+ return this.currentLimit;
146
+ }
147
+ /** The live limit in effect right now. */
148
+ get limit() {
149
+ return this.currentLimit;
150
+ }
151
+ /** `true` when the controller will move the limit on its own (adaptive mode). */
152
+ get isAdaptive() {
153
+ return this.resolved.mode === 'adaptive';
154
+ }
155
+ /**
156
+ * Start the control loop (adaptive mode only; fixed mode just takes a CPU baseline). The timer is
157
+ * `unref`'d so it never keeps the process alive; idempotent.
158
+ */
159
+ start() {
160
+ if (this.timer)
161
+ return;
162
+ if (!this.lastCpuUsage)
163
+ this.resetCpuBaseline();
164
+ if (!this.isAdaptive)
165
+ return;
166
+ this.timer = setInterval(() => this.tick(), this.tickMs);
167
+ this.timer.unref?.();
168
+ }
169
+ /** Stop the control loop (call on worker close). Idempotent. */
170
+ stop() {
171
+ if (this.timer) {
172
+ clearInterval(this.timer);
173
+ this.timer = undefined;
174
+ }
175
+ }
176
+ /** A task started — bump in-flight. Call from the job processor before awaiting the body. */
177
+ onStart() {
178
+ this.inFlightCount += 1;
179
+ }
180
+ /**
181
+ * A task settled. ALWAYS drops in-flight and counts toward stall liveness (`completionsThisTick`),
182
+ * so the saturation gate, the heartbeat `inFlight`, and the "alive-but-busy" signal see every task.
183
+ *
184
+ * `kind` gates the MEASUREMENT window: only `'step'` completions push a duration into the rolling
185
+ * window that feeds the latency gradient / throughput / p95 / error rate. A workflow TURN
186
+ * (`kind: 'workflow'`) is NOT measured — a 5ms suspend sitting next to a 2s step would corrupt the
187
+ * gradient — but it still counts as in-flight + forward progress. This is the single concurrency
188
+ * pool measuring steps only; the transport tags the kind when it routes a job by shape.
189
+ */
190
+ onSettle(durationMs, ok, kind) {
191
+ this.inFlightCount = Math.max(0, this.inFlightCount - 1);
192
+ // Forward progress for stall detection counts BOTH kinds — a worker churning workflow turns is
193
+ // not stalled even when no step settles this tick.
194
+ this.completionsThisTick += 1;
195
+ if (kind !== 'step')
196
+ return;
197
+ this.window.push({ durationMs, ok, at: this.now() });
198
+ if (this.window.length > WINDOW_SIZE)
199
+ this.window.shift();
200
+ }
201
+ /**
202
+ * One control-loop iteration: sample CPU, refresh the latency baseline, then decide the next limit
203
+ * and apply it. A no-op in fixed mode. Exposed (not private) so a test can drive ticks
204
+ * deterministically.
205
+ */
206
+ tick() {
207
+ if (this.resolved.mode !== 'adaptive' || !this.resolved.adaptive)
208
+ return;
209
+ this.sampleCpu(this.tickMs);
210
+ this.refreshRttLong();
211
+ // Stall = in-flight work but no completion this tick, sustained over STALL_TICKS.
212
+ if (this.inFlightCount > 0 && this.completionsThisTick === 0)
213
+ this.stallTicks += 1;
214
+ else
215
+ this.stallTicks = 0;
216
+ const stalled = this.stallTicks >= STALL_TICKS;
217
+ this.completionsThisTick = 0;
218
+ this.decide(this.resolved.adaptive, stalled);
219
+ }
220
+ resetCpuBaseline() {
221
+ this.lastCpuUsage = this.readCpuUsage();
222
+ this.lastCpuSampleAt = this.now();
223
+ }
224
+ /** Set `cpuPct` from the CPU time spent since the previous sample, over `elapsedMs` of wall time. */
225
+ sampleCpu(elapsedMs) {
226
+ const previous = this.lastCpuUsage;
227
+ this.resetCpuBaseline();
228
+ if (!previous || !this.lastCpuUsage || elapsedMs <= 0)
229
+ return;
230
+ // CpuUsage is microseconds of CPU; elapsedMs of wall time is elapsedMs*1000 micros per core.
231
+ const micros = this.lastCpuUsage.user - previous.user + (this.lastCpuUsage.system - previous.system);
232
+ const pct = (micros / (elapsedMs * 1000 * this.cpuCores)) * 100;
233
+ if (Number.isFinite(pct))
234
+ this.cpuPct = Math.max(0, pct);
235
+ }
236
+ /** Fixed mode has no control loop, so a snapshot samples CPU itself, at most once per tick period
237
+ * (several heartbeat keys snapshot back to back, and a near-zero span gives a meaningless rate). */
238
+ sampleCpuForSnapshot() {
239
+ if (this.isAdaptive)
240
+ return;
241
+ if (!this.lastCpuUsage) {
242
+ this.resetCpuBaseline();
243
+ return;
244
+ }
245
+ const elapsedMs = this.now() - this.lastCpuSampleAt;
246
+ if (elapsedMs >= this.tickMs)
247
+ this.sampleCpu(elapsedMs);
248
+ }
249
+ refreshRttLong() {
250
+ if (this.window.length === 0)
251
+ return;
252
+ let minDuration = this.window[0]?.durationMs ?? 0;
253
+ for (const c of this.window)
254
+ if (c.durationMs < minDuration)
255
+ minDuration = c.durationMs;
256
+ this.rttLongMs =
257
+ this.rttLongMs === undefined
258
+ ? minDuration
259
+ : RTT_LONG_EWMA_ALPHA * minDuration + (1 - RTT_LONG_EWMA_ALPHA) * this.rttLongMs;
260
+ }
261
+ rssPct() {
262
+ if (this.memoryLimitBytes <= 0)
263
+ return 0;
264
+ return (100 * this.readRss()) / this.memoryLimitBytes;
265
+ }
266
+ decide(cfg, stalled) {
267
+ const current = this.currentLimit;
268
+ const durations = this.window.map((c) => c.durationMs).sort((a, b) => a - b);
269
+ const p50 = percentile(durations, 50);
270
+ const errors = this.window.reduce((n, c) => n + (c.ok ? 0 : 1), 0);
271
+ const errorRate = this.window.length === 0 ? 0 : errors / this.window.length;
272
+ const gradient = this.rttLongMs !== undefined && p50 > 0 ? Math.min(1, this.rttLongMs / p50) : 1;
273
+ const rssPct = this.rssPct();
274
+ const saturated = this.inFlightCount >= current * 0.8;
275
+ let next = current;
276
+ let reason;
277
+ if (rssPct >= cfg.ramCeilingPct) {
278
+ next = Math.max(cfg.min, Math.floor(current * 0.8));
279
+ reason = 'ram_ceiling';
280
+ }
281
+ else if (cfg.cpuCeilingPct !== undefined && (this.cpuPct ?? 0) >= cfg.cpuCeilingPct) {
282
+ // CPU at/over the ceiling: never grow; shed one to relieve it.
283
+ next = Math.max(cfg.min, current - 1);
284
+ reason = 'cpu_ceiling';
285
+ }
286
+ else if (errorRate > 0.2 || stalled) {
287
+ next = Math.max(cfg.min, current - 1);
288
+ reason = 'backpressure';
289
+ }
290
+ else if (gradient < 0.7) {
291
+ next = Math.max(cfg.min, Math.floor(current * gradient));
292
+ reason = 'shrink';
293
+ }
294
+ else if (gradient >= 0.9 && saturated) {
295
+ next = Math.min(cfg.max, current + 1);
296
+ reason = 'grow';
297
+ }
298
+ next = clamp(next, cfg.min, cfg.max);
299
+ if (next === current || reason === undefined)
300
+ return;
301
+ this.currentLimit = next;
302
+ this.lastAdjust = { at: this.now(), from: current, to: next, reason };
303
+ this.apply(next);
304
+ }
305
+ /** The shared {@link WorkerStatus} the heartbeat writer stamps. Best-effort fields are omitted when
306
+ * unmeasured (no completions yet → no p95/throughput; no CPU sample yet → no `cpuPct`). */
307
+ snapshot() {
308
+ this.sampleCpuForSnapshot();
309
+ const durations = this.window.map((c) => c.durationMs).sort((a, b) => a - b);
310
+ const rssBytes = this.readRss();
311
+ const rssLimitBytes = this.memoryLimitBytes;
312
+ const status = {
313
+ runtime: 'node',
314
+ concurrency: {
315
+ mode: this.resolved.mode,
316
+ limit: this.currentLimit,
317
+ ...(this.resolved.mode === 'adaptive' && this.resolved.adaptive
318
+ ? { min: this.resolved.adaptive.min, max: this.resolved.adaptive.max }
319
+ : {}),
320
+ },
321
+ inFlight: this.inFlightCount,
322
+ rssBytes,
323
+ rssLimitBytes,
324
+ rssPct: rssLimitBytes > 0 ? (100 * rssBytes) / rssLimitBytes : 0,
325
+ };
326
+ if (this.cpuPct !== undefined)
327
+ status.cpuPct = this.cpuPct;
328
+ if (this.window.length > 0) {
329
+ status.throughputPerMin = this.throughputPerMin();
330
+ status.p95Ms = percentile(durations, 95);
331
+ }
332
+ if (this.lastAdjust)
333
+ status.lastAdjust = this.lastAdjust;
334
+ return status;
335
+ }
336
+ /**
337
+ * Completions per minute over the trailing minute: the window's completions from the last minute,
338
+ * over the span from the oldest of them (or a full minute, when the window reaches further back) to
339
+ * now, floored at a second. The rate decays while the worker is idle and reads 0 once a minute passes with no completion.
340
+ */
341
+ throughputPerMin() {
342
+ const first = this.window[0];
343
+ if (!first)
344
+ return 0;
345
+ const now = this.now();
346
+ const recent = this.window.filter((c) => now - c.at <= THROUGHPUT_WINDOW_MS).length;
347
+ if (recent === 0)
348
+ return 0;
349
+ const spanMs = clamp(now - first.at, THROUGHPUT_MIN_SPAN_MS, THROUGHPUT_WINDOW_MS);
350
+ return (recent / spanMs) * 60_000;
351
+ }
352
+ }
353
+ //# sourceMappingURL=adaptive-concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive-concurrency.js","sourceRoot":"","sources":["../../../src/transports/adaptive-concurrency.ts"],"names":[],"mappings":"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"}