@cadenza.io/service 2.17.3 → 2.17.5

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/index.d.mts CHANGED
@@ -209,6 +209,8 @@ type DistributedInquiryOptions = Partial<InquiryOptions> & {
209
209
  hydrationKey?: string;
210
210
  };
211
211
 
212
+ type RuntimeStatusState = "healthy" | "degraded" | "overloaded" | "unavailable";
213
+
212
214
  interface DeputyDescriptor {
213
215
  serviceName: string;
214
216
  remoteRoutineName?: string;
@@ -280,6 +282,34 @@ declare class ServiceRegistry {
280
282
  getInquiryResponderDescriptor(task: Task): InquiryResponderDescriptor;
281
283
  private getInstance;
282
284
  private getLocalInstance;
285
+ private summarizeTransportForDebug;
286
+ private summarizeInstanceForRuntimeStatusFallback;
287
+ private summarizeRuntimeStatusInquiryReports;
288
+ private createRuntimeStatusFallbackError;
289
+ resolveLocalStatusCheck(ctx?: AnyObject): {
290
+ __status: string;
291
+ __error: string;
292
+ errored: boolean;
293
+ } | {
294
+ __status: string;
295
+ __serviceName: string;
296
+ __serviceInstanceId: string;
297
+ __numberOfRunningGraphs: number;
298
+ __health: AnyObject;
299
+ __active: boolean;
300
+ reportedAt: string;
301
+ serviceName: string;
302
+ serviceInstanceId: string;
303
+ numberOfRunningGraphs: number;
304
+ health: AnyObject;
305
+ isActive: boolean;
306
+ isNonResponsive: boolean;
307
+ isBlocked: boolean;
308
+ state: RuntimeStatusState;
309
+ acceptingWork: boolean;
310
+ __error?: undefined;
311
+ errored?: undefined;
312
+ };
283
313
  private resolveTransportProtocolOrder;
284
314
  private selectTransportForInstance;
285
315
  private getRoutingTransportRole;
@@ -23122,8 +23152,6 @@ interface SSRInquiryBridge {
23122
23152
  }
23123
23153
  declare function createSSRInquiryBridge(options?: SSRInquiryBridgeOptions): SSRInquiryBridge;
23124
23154
 
23125
- type RuntimeStatusState = "healthy" | "degraded" | "overloaded" | "unavailable";
23126
-
23127
23155
  interface ServiceInstanceDescriptor {
23128
23156
  uuid: string;
23129
23157
  serviceName: string;
package/dist/index.d.ts CHANGED
@@ -209,6 +209,8 @@ type DistributedInquiryOptions = Partial<InquiryOptions> & {
209
209
  hydrationKey?: string;
210
210
  };
211
211
 
212
+ type RuntimeStatusState = "healthy" | "degraded" | "overloaded" | "unavailable";
213
+
212
214
  interface DeputyDescriptor {
213
215
  serviceName: string;
214
216
  remoteRoutineName?: string;
@@ -280,6 +282,34 @@ declare class ServiceRegistry {
280
282
  getInquiryResponderDescriptor(task: Task): InquiryResponderDescriptor;
281
283
  private getInstance;
282
284
  private getLocalInstance;
285
+ private summarizeTransportForDebug;
286
+ private summarizeInstanceForRuntimeStatusFallback;
287
+ private summarizeRuntimeStatusInquiryReports;
288
+ private createRuntimeStatusFallbackError;
289
+ resolveLocalStatusCheck(ctx?: AnyObject): {
290
+ __status: string;
291
+ __error: string;
292
+ errored: boolean;
293
+ } | {
294
+ __status: string;
295
+ __serviceName: string;
296
+ __serviceInstanceId: string;
297
+ __numberOfRunningGraphs: number;
298
+ __health: AnyObject;
299
+ __active: boolean;
300
+ reportedAt: string;
301
+ serviceName: string;
302
+ serviceInstanceId: string;
303
+ numberOfRunningGraphs: number;
304
+ health: AnyObject;
305
+ isActive: boolean;
306
+ isNonResponsive: boolean;
307
+ isBlocked: boolean;
308
+ state: RuntimeStatusState;
309
+ acceptingWork: boolean;
310
+ __error?: undefined;
311
+ errored?: undefined;
312
+ };
283
313
  private resolveTransportProtocolOrder;
284
314
  private selectTransportForInstance;
285
315
  private getRoutingTransportRole;
@@ -23122,8 +23152,6 @@ interface SSRInquiryBridge {
23122
23152
  }
23123
23153
  declare function createSSRInquiryBridge(options?: SSRInquiryBridgeOptions): SSRInquiryBridge;
23124
23154
 
23125
- type RuntimeStatusState = "healthy" | "degraded" | "overloaded" | "unavailable";
23126
-
23127
23155
  interface ServiceInstanceDescriptor {
23128
23156
  uuid: string;
23129
23157
  serviceName: string;
package/dist/index.js CHANGED
@@ -1624,50 +1624,10 @@ var ServiceRegistry = class _ServiceRegistry {
1624
1624
  "meta.service_registry.selected_instance_for_fetch",
1625
1625
  "meta.service_registry.socket_failed"
1626
1626
  );
1627
- this.getStatusTask = CadenzaService.createMetaTask("Get status", (ctx) => {
1628
- if (!this.serviceName) {
1629
- return {
1630
- __status: "error",
1631
- __error: "No service name defined",
1632
- errored: true
1633
- };
1634
- }
1635
- if (!this.serviceInstanceId) {
1636
- return {
1637
- __status: "error",
1638
- __error: "No service instance id defined",
1639
- errored: true
1640
- };
1641
- }
1642
- const report = this.buildLocalRuntimeStatusReport("full");
1643
- if (!report) {
1644
- return {
1645
- ...ctx,
1646
- __status: "error",
1647
- __error: "No local service instance available for status check",
1648
- errored: true
1649
- };
1650
- }
1651
- return {
1652
- ...ctx,
1653
- __status: "ok",
1654
- __serviceName: report.serviceName,
1655
- __serviceInstanceId: report.serviceInstanceId,
1656
- __numberOfRunningGraphs: report.numberOfRunningGraphs,
1657
- __health: report.health ?? {},
1658
- __active: report.isActive,
1659
- reportedAt: report.reportedAt,
1660
- serviceName: report.serviceName,
1661
- serviceInstanceId: report.serviceInstanceId,
1662
- numberOfRunningGraphs: report.numberOfRunningGraphs,
1663
- health: report.health ?? {},
1664
- isActive: report.isActive,
1665
- isNonResponsive: report.isNonResponsive,
1666
- isBlocked: report.isBlocked,
1667
- state: report.state,
1668
- acceptingWork: report.acceptingWork
1669
- };
1670
- }).doOn(
1627
+ this.getStatusTask = CadenzaService.createMetaTask(
1628
+ "Get status",
1629
+ (ctx) => this.resolveLocalStatusCheck(ctx)
1630
+ ).doOn(
1671
1631
  "meta.socket.status_check_requested",
1672
1632
  "meta.rest.status_check_requested"
1673
1633
  );
@@ -1884,12 +1844,14 @@ var ServiceRegistry = class _ServiceRegistry {
1884
1844
  this.useSocket ? "socket" : "rest"
1885
1845
  ) : void 0;
1886
1846
  const message = error instanceof Error ? error.message : String(error);
1847
+ const diagnostics = error && typeof error === "object" && "runtimeStatusFallback" in error && error.runtimeStatusFallback && typeof error.runtimeStatusFallback === "object" ? error.runtimeStatusFallback : void 0;
1887
1848
  CadenzaService.log(
1888
1849
  "Runtime status fallback inquiry failed.",
1889
1850
  {
1890
1851
  serviceName,
1891
1852
  serviceInstanceId,
1892
- error: message
1853
+ error: message,
1854
+ diagnostics
1893
1855
  },
1894
1856
  "warning"
1895
1857
  );
@@ -2379,6 +2341,110 @@ var ServiceRegistry = class _ServiceRegistry {
2379
2341
  }
2380
2342
  return this.getInstance(this.serviceName, this.serviceInstanceId);
2381
2343
  }
2344
+ summarizeTransportForDebug(transport) {
2345
+ if (!transport) {
2346
+ return void 0;
2347
+ }
2348
+ return {
2349
+ uuid: transport.uuid,
2350
+ role: transport.role,
2351
+ origin: transport.origin,
2352
+ protocols: transport.protocols,
2353
+ clientCreated: transport.clientCreated
2354
+ };
2355
+ }
2356
+ summarizeInstanceForRuntimeStatusFallback(instance) {
2357
+ return {
2358
+ exists: Boolean(instance),
2359
+ runtimeState: instance?.runtimeState,
2360
+ acceptingWork: instance?.acceptingWork,
2361
+ reportedAt: instance?.reportedAt ?? null,
2362
+ isDatabase: instance?.isDatabase,
2363
+ isFrontend: instance?.isFrontend,
2364
+ transports: (instance?.transports ?? []).map((transport) => ({
2365
+ uuid: transport.uuid,
2366
+ role: transport.role,
2367
+ origin: transport.origin,
2368
+ protocols: transport.protocols,
2369
+ clientCreated: transport.clientCreated
2370
+ }))
2371
+ };
2372
+ }
2373
+ summarizeRuntimeStatusInquiryReports(inquiryResult) {
2374
+ const reports = Array.isArray(inquiryResult.runtimeStatusReports) ? inquiryResult.runtimeStatusReports : [];
2375
+ return reports.map((candidate) => {
2376
+ const normalized = this.normalizeRuntimeStatusReport(candidate);
2377
+ if (normalized) {
2378
+ return {
2379
+ serviceName: normalized.serviceName,
2380
+ serviceInstanceId: normalized.serviceInstanceId,
2381
+ transportId: normalized.transportId,
2382
+ state: normalized.state,
2383
+ acceptingWork: normalized.acceptingWork,
2384
+ reportedAt: normalized.reportedAt
2385
+ };
2386
+ }
2387
+ const raw = candidate && typeof candidate === "object" ? candidate : {};
2388
+ const rawState = raw.state === "healthy" || raw.state === "degraded" || raw.state === "overloaded" || raw.state === "unavailable" ? raw.state : void 0;
2389
+ return {
2390
+ serviceName: typeof raw.serviceName === "string" ? raw.serviceName : typeof raw.__serviceName === "string" ? raw.__serviceName : void 0,
2391
+ serviceInstanceId: typeof raw.serviceInstanceId === "string" ? raw.serviceInstanceId : typeof raw.__serviceInstanceId === "string" ? raw.__serviceInstanceId : void 0,
2392
+ transportId: typeof raw.transportId === "string" ? raw.transportId : typeof raw.serviceTransportId === "string" ? raw.serviceTransportId : void 0,
2393
+ state: rawState,
2394
+ acceptingWork: typeof raw.acceptingWork === "boolean" ? raw.acceptingWork : void 0,
2395
+ reportedAt: typeof raw.reportedAt === "string" ? raw.reportedAt : void 0
2396
+ };
2397
+ });
2398
+ }
2399
+ createRuntimeStatusFallbackError(message, diagnostics) {
2400
+ return Object.assign(new Error(message), {
2401
+ runtimeStatusFallback: diagnostics
2402
+ });
2403
+ }
2404
+ resolveLocalStatusCheck(ctx = {}) {
2405
+ if (!this.serviceName) {
2406
+ return {
2407
+ __status: "error",
2408
+ __error: "No service name defined",
2409
+ errored: true
2410
+ };
2411
+ }
2412
+ if (!this.serviceInstanceId) {
2413
+ return {
2414
+ __status: "error",
2415
+ __error: "No service instance id defined",
2416
+ errored: true
2417
+ };
2418
+ }
2419
+ const report = this.buildLocalRuntimeStatusReport("full");
2420
+ if (!report) {
2421
+ return {
2422
+ ...ctx,
2423
+ __status: "error",
2424
+ __error: "No local service instance available for status check",
2425
+ errored: true
2426
+ };
2427
+ }
2428
+ return {
2429
+ ...ctx,
2430
+ __status: "ok",
2431
+ __serviceName: report.serviceName,
2432
+ __serviceInstanceId: report.serviceInstanceId,
2433
+ __numberOfRunningGraphs: report.numberOfRunningGraphs,
2434
+ __health: report.health ?? {},
2435
+ __active: report.isActive,
2436
+ reportedAt: report.reportedAt,
2437
+ serviceName: report.serviceName,
2438
+ serviceInstanceId: report.serviceInstanceId,
2439
+ numberOfRunningGraphs: report.numberOfRunningGraphs,
2440
+ health: report.health ?? {},
2441
+ isActive: report.isActive,
2442
+ isNonResponsive: report.isNonResponsive,
2443
+ isBlocked: report.isBlocked,
2444
+ state: report.state,
2445
+ acceptingWork: report.acceptingWork
2446
+ };
2447
+ }
2382
2448
  resolveTransportProtocolOrder(ctx) {
2383
2449
  const explicit = ctx.__preferredTransportProtocol === "rest" || ctx.__preferredTransportProtocol === "socket" ? ctx.__preferredTransportProtocol : void 0;
2384
2450
  const preferred = explicit ?? (this.useSocket ? "socket" : "rest");
@@ -2654,32 +2720,48 @@ var ServiceRegistry = class _ServiceRegistry {
2654
2720
  }
2655
2721
  async resolveRuntimeStatusFallbackInquiry(serviceName, serviceInstanceId, options = {}) {
2656
2722
  const instance = this.getInstance(serviceName, serviceInstanceId);
2657
- if (instance) {
2658
- const directReport = await this.requestRuntimeStatusViaRest(
2659
- instance,
2660
- serviceName,
2661
- serviceInstanceId
2662
- );
2663
- if (directReport) {
2664
- if (!this.applyRuntimeStatusReport(directReport)) {
2665
- throw new Error(
2666
- `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`
2667
- );
2668
- }
2669
- this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
2670
- this.missedHeartbeatsByInstance.set(serviceInstanceId, 0);
2671
- return {
2672
- report: directReport,
2673
- inquiryMeta: {
2674
- inquiry: META_RUNTIME_STATUS_INTENT,
2675
- responded: 1,
2676
- failed: 0,
2677
- timedOut: 0,
2678
- pending: 0,
2679
- directStatusCheck: true
2723
+ const directStatusCheck = instance ? await this.requestRuntimeStatusViaRest(
2724
+ instance,
2725
+ serviceName,
2726
+ serviceInstanceId
2727
+ ) : {
2728
+ report: null,
2729
+ diagnostic: {
2730
+ attempted: false,
2731
+ outcome: "instance_missing"
2732
+ }
2733
+ };
2734
+ if (directStatusCheck.report) {
2735
+ if (!this.applyRuntimeStatusReport(directStatusCheck.report)) {
2736
+ throw this.createRuntimeStatusFallbackError(
2737
+ `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`,
2738
+ {
2739
+ target: {
2740
+ serviceName,
2741
+ serviceInstanceId
2742
+ },
2743
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2744
+ directStatusCheck: directStatusCheck.diagnostic,
2745
+ inquiry: {
2746
+ meta: {},
2747
+ reportTargets: []
2748
+ }
2680
2749
  }
2681
- };
2750
+ );
2682
2751
  }
2752
+ this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
2753
+ this.missedHeartbeatsByInstance.set(serviceInstanceId, 0);
2754
+ return {
2755
+ report: directStatusCheck.report,
2756
+ inquiryMeta: {
2757
+ inquiry: META_RUNTIME_STATUS_INTENT,
2758
+ responded: 1,
2759
+ failed: 0,
2760
+ timedOut: 0,
2761
+ pending: 0,
2762
+ directStatusCheck: true
2763
+ }
2764
+ };
2683
2765
  }
2684
2766
  const inquiryResult = await CadenzaService.inquire(
2685
2767
  META_RUNTIME_STATUS_INTENT,
@@ -2701,13 +2783,37 @@ var ServiceRegistry = class _ServiceRegistry {
2701
2783
  serviceInstanceId
2702
2784
  );
2703
2785
  if (!report) {
2704
- throw new Error(
2705
- `No runtime status report for ${serviceName}/${serviceInstanceId}`
2786
+ throw this.createRuntimeStatusFallbackError(
2787
+ `No runtime status report for ${serviceName}/${serviceInstanceId}`,
2788
+ {
2789
+ target: {
2790
+ serviceName,
2791
+ serviceInstanceId
2792
+ },
2793
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2794
+ directStatusCheck: directStatusCheck.diagnostic,
2795
+ inquiry: {
2796
+ meta: inquiryResult.__inquiryMeta && typeof inquiryResult.__inquiryMeta === "object" ? inquiryResult.__inquiryMeta : {},
2797
+ reportTargets: this.summarizeRuntimeStatusInquiryReports(inquiryResult)
2798
+ }
2799
+ }
2706
2800
  );
2707
2801
  }
2708
2802
  if (!this.applyRuntimeStatusReport(report)) {
2709
- throw new Error(
2710
- `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`
2803
+ throw this.createRuntimeStatusFallbackError(
2804
+ `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`,
2805
+ {
2806
+ target: {
2807
+ serviceName,
2808
+ serviceInstanceId
2809
+ },
2810
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2811
+ directStatusCheck: directStatusCheck.diagnostic,
2812
+ inquiry: {
2813
+ meta: inquiryResult.__inquiryMeta && typeof inquiryResult.__inquiryMeta === "object" ? inquiryResult.__inquiryMeta : {},
2814
+ reportTargets: this.summarizeRuntimeStatusInquiryReports(inquiryResult)
2815
+ }
2816
+ }
2711
2817
  );
2712
2818
  }
2713
2819
  this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
@@ -2719,11 +2825,23 @@ var ServiceRegistry = class _ServiceRegistry {
2719
2825
  }
2720
2826
  async requestRuntimeStatusViaRest(instance, serviceName, serviceInstanceId) {
2721
2827
  if (typeof globalThis.fetch !== "function") {
2722
- return null;
2828
+ return {
2829
+ report: null,
2830
+ diagnostic: {
2831
+ attempted: false,
2832
+ outcome: "fetch_unavailable"
2833
+ }
2834
+ };
2723
2835
  }
2724
2836
  const transport = this.getRouteableTransport(instance, "rest");
2725
2837
  if (!transport) {
2726
- return null;
2838
+ return {
2839
+ report: null,
2840
+ diagnostic: {
2841
+ attempted: false,
2842
+ outcome: "no_rest_transport"
2843
+ }
2844
+ };
2727
2845
  }
2728
2846
  const controller = typeof AbortController === "function" ? new AbortController() : null;
2729
2847
  const timeoutId = controller ? setTimeout(() => controller.abort(), this.runtimeStatusFallbackTimeoutMs) : null;
@@ -2733,7 +2851,16 @@ var ServiceRegistry = class _ServiceRegistry {
2733
2851
  signal: controller?.signal
2734
2852
  });
2735
2853
  if ("ok" in response && response.ok === false) {
2736
- return null;
2854
+ return {
2855
+ report: null,
2856
+ diagnostic: {
2857
+ attempted: true,
2858
+ outcome: "http_error",
2859
+ transport: this.summarizeTransportForDebug(transport),
2860
+ responseStatus: typeof response.status === "number" ? response.status : void 0,
2861
+ responseStatusText: typeof response.statusText === "string" ? response.statusText : void 0
2862
+ }
2863
+ };
2737
2864
  }
2738
2865
  const payload = typeof response.json === "function" ? await response.json() : response;
2739
2866
  const report = this.normalizeRuntimeStatusReport({
@@ -2743,14 +2870,46 @@ var ServiceRegistry = class _ServiceRegistry {
2743
2870
  transportProtocols: payload?.transportProtocols ?? transport.protocols
2744
2871
  });
2745
2872
  if (!report) {
2746
- return null;
2873
+ return {
2874
+ report: null,
2875
+ diagnostic: {
2876
+ attempted: true,
2877
+ outcome: "invalid_report",
2878
+ transport: this.summarizeTransportForDebug(transport),
2879
+ payloadKeys: payload && typeof payload === "object" ? Object.keys(payload).sort() : []
2880
+ }
2881
+ };
2747
2882
  }
2748
2883
  if (report.serviceName !== serviceName || report.serviceInstanceId !== serviceInstanceId) {
2749
- return null;
2884
+ return {
2885
+ report: null,
2886
+ diagnostic: {
2887
+ attempted: true,
2888
+ outcome: "identity_mismatch",
2889
+ transport: this.summarizeTransportForDebug(transport),
2890
+ payloadServiceName: report.serviceName,
2891
+ payloadServiceInstanceId: report.serviceInstanceId
2892
+ }
2893
+ };
2750
2894
  }
2751
- return report;
2752
- } catch {
2753
- return null;
2895
+ return {
2896
+ report,
2897
+ diagnostic: {
2898
+ attempted: true,
2899
+ outcome: "matched",
2900
+ transport: this.summarizeTransportForDebug(transport)
2901
+ }
2902
+ };
2903
+ } catch (error) {
2904
+ return {
2905
+ report: null,
2906
+ diagnostic: {
2907
+ attempted: true,
2908
+ outcome: "fetch_error",
2909
+ transport: this.summarizeTransportForDebug(transport),
2910
+ error: error instanceof Error ? error.message : String(error)
2911
+ }
2912
+ };
2754
2913
  } finally {
2755
2914
  if (timeoutId) {
2756
2915
  clearTimeout(timeoutId);
@@ -3258,15 +3417,11 @@ var RestController = class _RestController {
3258
3417
  CadenzaService.emit(ctx2.__signalName, ctx2);
3259
3418
  });
3260
3419
  app.get("/status", (req, res) => {
3261
- CadenzaService.createEphemeralMetaTask(
3262
- "Resolve status check",
3263
- (statusCtx) => res.json(statusCtx),
3264
- "Resolves a status check request",
3265
- { register: false }
3266
- ).doAfter(CadenzaService.serviceRegistry.getStatusTask);
3267
- CadenzaService.emit(
3268
- "meta.rest.status_check_requested",
3269
- req.body.query
3420
+ const statusCheckQuery = req?.body?.query && typeof req.body.query === "object" ? req.body.query : req?.query && typeof req.query === "object" ? { ...req.query } : {};
3421
+ res.json(
3422
+ CadenzaService.serviceRegistry.resolveLocalStatusCheck(
3423
+ statusCheckQuery
3424
+ )
3270
3425
  );
3271
3426
  });
3272
3427
  return true;
@@ -4338,13 +4493,7 @@ var SocketController = class _SocketController {
4338
4493
  ws.on(
4339
4494
  "status_check",
4340
4495
  (ctx, callback) => {
4341
- CadenzaService.createEphemeralMetaTask(
4342
- "Resolve status check",
4343
- callback,
4344
- "Resolves a status check request",
4345
- { register: false }
4346
- ).doAfter(CadenzaService.serviceRegistry.getStatusTask);
4347
- CadenzaService.emit("meta.socket.status_check_requested", ctx);
4496
+ callback(CadenzaService.serviceRegistry.resolveLocalStatusCheck(ctx));
4348
4497
  }
4349
4498
  );
4350
4499
  ws.on("disconnect", () => {