@winkjs/composer 0.6.0 → 0.8.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 (39) hide show
  1. package/README.md +2 -2
  2. package/package.json +2 -2
  3. package/src/composer.js +1 -1
  4. package/src/core/emitter-manager/mqtt/connection.js +209 -0
  5. package/src/core/emitter-manager/mqtt/constants.js +43 -29
  6. package/src/core/emitter-manager/mqtt/emitter.js +103 -658
  7. package/src/core/emitter-manager/mqtt/health.js +151 -0
  8. package/src/core/emitter-manager/mqtt/index.js +68 -4
  9. package/src/core/emitter-manager/mqtt/publish.js +292 -0
  10. package/src/core/emitter-manager/mqtt/resolve-config.js +312 -0
  11. package/src/core/emitter-manager/mqtt/shutdown-drain.js +247 -0
  12. package/src/core/emitter-manager/terminal/index.js +16 -1
  13. package/src/core/env-vars.js +92 -24
  14. package/src/core/logger/index.js +1 -1
  15. package/src/core/source-manager/mqtt/client.js +197 -63
  16. package/src/core/source-manager/mqtt/dedup.js +16 -11
  17. package/src/core/source-manager/mqtt/index.js +32 -5
  18. package/src/core/source-manager/mqtt/status.js +168 -56
  19. package/src/core/storage-manager/questdb/address-policy.js +264 -0
  20. package/src/core/storage-manager/questdb/delivery-gate.js +218 -0
  21. package/src/core/storage-manager/questdb/flush-engine.js +852 -0
  22. package/src/core/storage-manager/questdb/flush-tracker.js +331 -0
  23. package/src/core/storage-manager/questdb/index.js +542 -862
  24. package/src/core/storage-manager/questdb/persist-plan.js +128 -167
  25. package/src/core/storage-manager/questdb/resolve-options.js +266 -0
  26. package/src/core/storage-manager/questdb/shutdown-drain.js +181 -0
  27. package/src/core/storage-manager/questdb/skip-warnings.js +180 -0
  28. package/src/core/test-utils/tcp-proxy.js +194 -1
  29. package/src/core/utils/address/index.js +362 -0
  30. package/src/core/utils/address/probe.js +210 -0
  31. package/src/core/utils/callback-guard/index.js +23 -2
  32. package/src/core/utils/clock/index.js +34 -0
  33. package/src/core/utils/jitter/index.js +51 -0
  34. package/src/core/utils/line-rate/index.js +104 -0
  35. package/src/core/utils/quantize/index.js +43 -19
  36. package/src/core/wiring/wire-emitters.js +3 -1
  37. package/src/core/wiring/wire-storages.js +10 -2
  38. package/src/flow/flow.js +24 -3
  39. package/src/flow/run.js +24 -2
package/src/flow/run.js CHANGED
@@ -272,6 +272,21 @@ export const runFlow = async function ( flowName, specsOrSpecsByCase, importSet,
272
272
  }
273
273
  }; // runDrainStage()
274
274
 
275
+ // A sink stage returns `Promise.allSettled` results. The wiring
276
+ // logs each adapter whose drain rejected and lets its siblings
277
+ // finish, so one failing sink never strands another's data. The
278
+ // loss must still reach this handle's caller. A rejected drain is
279
+ // how the shutdown manager knows to exit 1 (ADR-018 §7). So once
280
+ // every adapter in the stage has drained, the stage throws the
281
+ // first rejected reason, code and dropped count intact.
282
+ const throwFirstRejection = function ( results ) {
283
+ for ( let i = 0; i < results.length; i += 1 ) {
284
+ if ( results[ i ].status === 'rejected' ) {
285
+ throw results[ i ].reason;
286
+ }
287
+ }
288
+ }; // throwFirstRejection()
289
+
275
290
  const drainAll = async function () {
276
291
  const stageErrors = [];
277
292
  try {
@@ -281,9 +296,9 @@ export const runFlow = async function ( flowName, specsOrSpecsByCase, importSet,
281
296
  () => stopSource( { timeout: STAGE_TIMEOUT_MS } ) );
282
297
  }
283
298
  await runDrainStage( 'emitter', stageErrors,
284
- () => emitters.shutdown( { timeout: STAGE_TIMEOUT_MS } ) );
299
+ async () => throwFirstRejection( await emitters.shutdown( { timeout: STAGE_TIMEOUT_MS } ) ) );
285
300
  await runDrainStage( 'storage', stageErrors,
286
- () => storages.shutdown( { timeout: STAGE_TIMEOUT_MS } ) );
301
+ async () => throwFirstRejection( await storages.shutdown( { timeout: STAGE_TIMEOUT_MS } ) ) );
287
302
  } finally {
288
303
  // Whatever the path here — clean drain or a stage that threw —
289
304
  // the source has stopped producing, so unblock any
@@ -311,8 +326,15 @@ export const runFlow = async function ( flowName, specsOrSpecsByCase, importSet,
311
326
  // the process as unhandled. The classified log keeps the loss
312
327
  // loud without the crash, and a caller that later awaits
313
328
  // `handle.shutdown()` still receives the memoized rejection.
329
+ //
330
+ // The exit code carries the loss too. This drain has no awaiting
331
+ // caller, and the flow left the shutdown manager's list when the
332
+ // drain began, so no other path can set it. A batch script that
333
+ // replays a file and loses rows at the end must exit 1, the same
334
+ // as the signal path does (ADR-018 §7).
314
335
  const observedShutdown = function () {
315
336
  shutdown().catch( function ( err ) {
337
+ process.exitCode = 1;
316
338
  logger.error(
317
339
  `winkComposer/flow '${flowName}': shutdown failed ` +
318
340
  `[${( err && err.code ) || 'UNKNOWN'}]: ${( err && err.message ) || String( err )}`