@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.
@@ -1573,50 +1573,10 @@ var ServiceRegistry = class _ServiceRegistry {
1573
1573
  "meta.service_registry.selected_instance_for_fetch",
1574
1574
  "meta.service_registry.socket_failed"
1575
1575
  );
1576
- this.getStatusTask = CadenzaService.createMetaTask("Get status", (ctx) => {
1577
- if (!this.serviceName) {
1578
- return {
1579
- __status: "error",
1580
- __error: "No service name defined",
1581
- errored: true
1582
- };
1583
- }
1584
- if (!this.serviceInstanceId) {
1585
- return {
1586
- __status: "error",
1587
- __error: "No service instance id defined",
1588
- errored: true
1589
- };
1590
- }
1591
- const report = this.buildLocalRuntimeStatusReport("full");
1592
- if (!report) {
1593
- return {
1594
- ...ctx,
1595
- __status: "error",
1596
- __error: "No local service instance available for status check",
1597
- errored: true
1598
- };
1599
- }
1600
- return {
1601
- ...ctx,
1602
- __status: "ok",
1603
- __serviceName: report.serviceName,
1604
- __serviceInstanceId: report.serviceInstanceId,
1605
- __numberOfRunningGraphs: report.numberOfRunningGraphs,
1606
- __health: report.health ?? {},
1607
- __active: report.isActive,
1608
- reportedAt: report.reportedAt,
1609
- serviceName: report.serviceName,
1610
- serviceInstanceId: report.serviceInstanceId,
1611
- numberOfRunningGraphs: report.numberOfRunningGraphs,
1612
- health: report.health ?? {},
1613
- isActive: report.isActive,
1614
- isNonResponsive: report.isNonResponsive,
1615
- isBlocked: report.isBlocked,
1616
- state: report.state,
1617
- acceptingWork: report.acceptingWork
1618
- };
1619
- }).doOn(
1576
+ this.getStatusTask = CadenzaService.createMetaTask(
1577
+ "Get status",
1578
+ (ctx) => this.resolveLocalStatusCheck(ctx)
1579
+ ).doOn(
1620
1580
  "meta.socket.status_check_requested",
1621
1581
  "meta.rest.status_check_requested"
1622
1582
  );
@@ -1833,12 +1793,14 @@ var ServiceRegistry = class _ServiceRegistry {
1833
1793
  this.useSocket ? "socket" : "rest"
1834
1794
  ) : void 0;
1835
1795
  const message = error instanceof Error ? error.message : String(error);
1796
+ const diagnostics = error && typeof error === "object" && "runtimeStatusFallback" in error && error.runtimeStatusFallback && typeof error.runtimeStatusFallback === "object" ? error.runtimeStatusFallback : void 0;
1836
1797
  CadenzaService.log(
1837
1798
  "Runtime status fallback inquiry failed.",
1838
1799
  {
1839
1800
  serviceName,
1840
1801
  serviceInstanceId,
1841
- error: message
1802
+ error: message,
1803
+ diagnostics
1842
1804
  },
1843
1805
  "warning"
1844
1806
  );
@@ -2328,6 +2290,110 @@ var ServiceRegistry = class _ServiceRegistry {
2328
2290
  }
2329
2291
  return this.getInstance(this.serviceName, this.serviceInstanceId);
2330
2292
  }
2293
+ summarizeTransportForDebug(transport) {
2294
+ if (!transport) {
2295
+ return void 0;
2296
+ }
2297
+ return {
2298
+ uuid: transport.uuid,
2299
+ role: transport.role,
2300
+ origin: transport.origin,
2301
+ protocols: transport.protocols,
2302
+ clientCreated: transport.clientCreated
2303
+ };
2304
+ }
2305
+ summarizeInstanceForRuntimeStatusFallback(instance) {
2306
+ return {
2307
+ exists: Boolean(instance),
2308
+ runtimeState: instance?.runtimeState,
2309
+ acceptingWork: instance?.acceptingWork,
2310
+ reportedAt: instance?.reportedAt ?? null,
2311
+ isDatabase: instance?.isDatabase,
2312
+ isFrontend: instance?.isFrontend,
2313
+ transports: (instance?.transports ?? []).map((transport) => ({
2314
+ uuid: transport.uuid,
2315
+ role: transport.role,
2316
+ origin: transport.origin,
2317
+ protocols: transport.protocols,
2318
+ clientCreated: transport.clientCreated
2319
+ }))
2320
+ };
2321
+ }
2322
+ summarizeRuntimeStatusInquiryReports(inquiryResult) {
2323
+ const reports = Array.isArray(inquiryResult.runtimeStatusReports) ? inquiryResult.runtimeStatusReports : [];
2324
+ return reports.map((candidate) => {
2325
+ const normalized = this.normalizeRuntimeStatusReport(candidate);
2326
+ if (normalized) {
2327
+ return {
2328
+ serviceName: normalized.serviceName,
2329
+ serviceInstanceId: normalized.serviceInstanceId,
2330
+ transportId: normalized.transportId,
2331
+ state: normalized.state,
2332
+ acceptingWork: normalized.acceptingWork,
2333
+ reportedAt: normalized.reportedAt
2334
+ };
2335
+ }
2336
+ const raw = candidate && typeof candidate === "object" ? candidate : {};
2337
+ const rawState = raw.state === "healthy" || raw.state === "degraded" || raw.state === "overloaded" || raw.state === "unavailable" ? raw.state : void 0;
2338
+ return {
2339
+ serviceName: typeof raw.serviceName === "string" ? raw.serviceName : typeof raw.__serviceName === "string" ? raw.__serviceName : void 0,
2340
+ serviceInstanceId: typeof raw.serviceInstanceId === "string" ? raw.serviceInstanceId : typeof raw.__serviceInstanceId === "string" ? raw.__serviceInstanceId : void 0,
2341
+ transportId: typeof raw.transportId === "string" ? raw.transportId : typeof raw.serviceTransportId === "string" ? raw.serviceTransportId : void 0,
2342
+ state: rawState,
2343
+ acceptingWork: typeof raw.acceptingWork === "boolean" ? raw.acceptingWork : void 0,
2344
+ reportedAt: typeof raw.reportedAt === "string" ? raw.reportedAt : void 0
2345
+ };
2346
+ });
2347
+ }
2348
+ createRuntimeStatusFallbackError(message, diagnostics) {
2349
+ return Object.assign(new Error(message), {
2350
+ runtimeStatusFallback: diagnostics
2351
+ });
2352
+ }
2353
+ resolveLocalStatusCheck(ctx = {}) {
2354
+ if (!this.serviceName) {
2355
+ return {
2356
+ __status: "error",
2357
+ __error: "No service name defined",
2358
+ errored: true
2359
+ };
2360
+ }
2361
+ if (!this.serviceInstanceId) {
2362
+ return {
2363
+ __status: "error",
2364
+ __error: "No service instance id defined",
2365
+ errored: true
2366
+ };
2367
+ }
2368
+ const report = this.buildLocalRuntimeStatusReport("full");
2369
+ if (!report) {
2370
+ return {
2371
+ ...ctx,
2372
+ __status: "error",
2373
+ __error: "No local service instance available for status check",
2374
+ errored: true
2375
+ };
2376
+ }
2377
+ return {
2378
+ ...ctx,
2379
+ __status: "ok",
2380
+ __serviceName: report.serviceName,
2381
+ __serviceInstanceId: report.serviceInstanceId,
2382
+ __numberOfRunningGraphs: report.numberOfRunningGraphs,
2383
+ __health: report.health ?? {},
2384
+ __active: report.isActive,
2385
+ reportedAt: report.reportedAt,
2386
+ serviceName: report.serviceName,
2387
+ serviceInstanceId: report.serviceInstanceId,
2388
+ numberOfRunningGraphs: report.numberOfRunningGraphs,
2389
+ health: report.health ?? {},
2390
+ isActive: report.isActive,
2391
+ isNonResponsive: report.isNonResponsive,
2392
+ isBlocked: report.isBlocked,
2393
+ state: report.state,
2394
+ acceptingWork: report.acceptingWork
2395
+ };
2396
+ }
2331
2397
  resolveTransportProtocolOrder(ctx) {
2332
2398
  const explicit = ctx.__preferredTransportProtocol === "rest" || ctx.__preferredTransportProtocol === "socket" ? ctx.__preferredTransportProtocol : void 0;
2333
2399
  const preferred = explicit ?? (this.useSocket ? "socket" : "rest");
@@ -2603,32 +2669,48 @@ var ServiceRegistry = class _ServiceRegistry {
2603
2669
  }
2604
2670
  async resolveRuntimeStatusFallbackInquiry(serviceName, serviceInstanceId, options = {}) {
2605
2671
  const instance = this.getInstance(serviceName, serviceInstanceId);
2606
- if (instance) {
2607
- const directReport = await this.requestRuntimeStatusViaRest(
2608
- instance,
2609
- serviceName,
2610
- serviceInstanceId
2611
- );
2612
- if (directReport) {
2613
- if (!this.applyRuntimeStatusReport(directReport)) {
2614
- throw new Error(
2615
- `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`
2616
- );
2617
- }
2618
- this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
2619
- this.missedHeartbeatsByInstance.set(serviceInstanceId, 0);
2620
- return {
2621
- report: directReport,
2622
- inquiryMeta: {
2623
- inquiry: META_RUNTIME_STATUS_INTENT,
2624
- responded: 1,
2625
- failed: 0,
2626
- timedOut: 0,
2627
- pending: 0,
2628
- directStatusCheck: true
2672
+ const directStatusCheck = instance ? await this.requestRuntimeStatusViaRest(
2673
+ instance,
2674
+ serviceName,
2675
+ serviceInstanceId
2676
+ ) : {
2677
+ report: null,
2678
+ diagnostic: {
2679
+ attempted: false,
2680
+ outcome: "instance_missing"
2681
+ }
2682
+ };
2683
+ if (directStatusCheck.report) {
2684
+ if (!this.applyRuntimeStatusReport(directStatusCheck.report)) {
2685
+ throw this.createRuntimeStatusFallbackError(
2686
+ `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`,
2687
+ {
2688
+ target: {
2689
+ serviceName,
2690
+ serviceInstanceId
2691
+ },
2692
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2693
+ directStatusCheck: directStatusCheck.diagnostic,
2694
+ inquiry: {
2695
+ meta: {},
2696
+ reportTargets: []
2697
+ }
2629
2698
  }
2630
- };
2699
+ );
2631
2700
  }
2701
+ this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
2702
+ this.missedHeartbeatsByInstance.set(serviceInstanceId, 0);
2703
+ return {
2704
+ report: directStatusCheck.report,
2705
+ inquiryMeta: {
2706
+ inquiry: META_RUNTIME_STATUS_INTENT,
2707
+ responded: 1,
2708
+ failed: 0,
2709
+ timedOut: 0,
2710
+ pending: 0,
2711
+ directStatusCheck: true
2712
+ }
2713
+ };
2632
2714
  }
2633
2715
  const inquiryResult = await CadenzaService.inquire(
2634
2716
  META_RUNTIME_STATUS_INTENT,
@@ -2650,13 +2732,37 @@ var ServiceRegistry = class _ServiceRegistry {
2650
2732
  serviceInstanceId
2651
2733
  );
2652
2734
  if (!report) {
2653
- throw new Error(
2654
- `No runtime status report for ${serviceName}/${serviceInstanceId}`
2735
+ throw this.createRuntimeStatusFallbackError(
2736
+ `No runtime status report for ${serviceName}/${serviceInstanceId}`,
2737
+ {
2738
+ target: {
2739
+ serviceName,
2740
+ serviceInstanceId
2741
+ },
2742
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2743
+ directStatusCheck: directStatusCheck.diagnostic,
2744
+ inquiry: {
2745
+ meta: inquiryResult.__inquiryMeta && typeof inquiryResult.__inquiryMeta === "object" ? inquiryResult.__inquiryMeta : {},
2746
+ reportTargets: this.summarizeRuntimeStatusInquiryReports(inquiryResult)
2747
+ }
2748
+ }
2655
2749
  );
2656
2750
  }
2657
2751
  if (!this.applyRuntimeStatusReport(report)) {
2658
- throw new Error(
2659
- `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`
2752
+ throw this.createRuntimeStatusFallbackError(
2753
+ `No tracked instance for runtime fallback ${serviceName}/${serviceInstanceId}`,
2754
+ {
2755
+ target: {
2756
+ serviceName,
2757
+ serviceInstanceId
2758
+ },
2759
+ instance: this.summarizeInstanceForRuntimeStatusFallback(instance),
2760
+ directStatusCheck: directStatusCheck.diagnostic,
2761
+ inquiry: {
2762
+ meta: inquiryResult.__inquiryMeta && typeof inquiryResult.__inquiryMeta === "object" ? inquiryResult.__inquiryMeta : {},
2763
+ reportTargets: this.summarizeRuntimeStatusInquiryReports(inquiryResult)
2764
+ }
2765
+ }
2660
2766
  );
2661
2767
  }
2662
2768
  this.lastHeartbeatAtByInstance.set(serviceInstanceId, Date.now());
@@ -2668,11 +2774,23 @@ var ServiceRegistry = class _ServiceRegistry {
2668
2774
  }
2669
2775
  async requestRuntimeStatusViaRest(instance, serviceName, serviceInstanceId) {
2670
2776
  if (typeof globalThis.fetch !== "function") {
2671
- return null;
2777
+ return {
2778
+ report: null,
2779
+ diagnostic: {
2780
+ attempted: false,
2781
+ outcome: "fetch_unavailable"
2782
+ }
2783
+ };
2672
2784
  }
2673
2785
  const transport = this.getRouteableTransport(instance, "rest");
2674
2786
  if (!transport) {
2675
- return null;
2787
+ return {
2788
+ report: null,
2789
+ diagnostic: {
2790
+ attempted: false,
2791
+ outcome: "no_rest_transport"
2792
+ }
2793
+ };
2676
2794
  }
2677
2795
  const controller = typeof AbortController === "function" ? new AbortController() : null;
2678
2796
  const timeoutId = controller ? setTimeout(() => controller.abort(), this.runtimeStatusFallbackTimeoutMs) : null;
@@ -2682,7 +2800,16 @@ var ServiceRegistry = class _ServiceRegistry {
2682
2800
  signal: controller?.signal
2683
2801
  });
2684
2802
  if ("ok" in response && response.ok === false) {
2685
- return null;
2803
+ return {
2804
+ report: null,
2805
+ diagnostic: {
2806
+ attempted: true,
2807
+ outcome: "http_error",
2808
+ transport: this.summarizeTransportForDebug(transport),
2809
+ responseStatus: typeof response.status === "number" ? response.status : void 0,
2810
+ responseStatusText: typeof response.statusText === "string" ? response.statusText : void 0
2811
+ }
2812
+ };
2686
2813
  }
2687
2814
  const payload = typeof response.json === "function" ? await response.json() : response;
2688
2815
  const report = this.normalizeRuntimeStatusReport({
@@ -2692,14 +2819,46 @@ var ServiceRegistry = class _ServiceRegistry {
2692
2819
  transportProtocols: payload?.transportProtocols ?? transport.protocols
2693
2820
  });
2694
2821
  if (!report) {
2695
- return null;
2822
+ return {
2823
+ report: null,
2824
+ diagnostic: {
2825
+ attempted: true,
2826
+ outcome: "invalid_report",
2827
+ transport: this.summarizeTransportForDebug(transport),
2828
+ payloadKeys: payload && typeof payload === "object" ? Object.keys(payload).sort() : []
2829
+ }
2830
+ };
2696
2831
  }
2697
2832
  if (report.serviceName !== serviceName || report.serviceInstanceId !== serviceInstanceId) {
2698
- return null;
2833
+ return {
2834
+ report: null,
2835
+ diagnostic: {
2836
+ attempted: true,
2837
+ outcome: "identity_mismatch",
2838
+ transport: this.summarizeTransportForDebug(transport),
2839
+ payloadServiceName: report.serviceName,
2840
+ payloadServiceInstanceId: report.serviceInstanceId
2841
+ }
2842
+ };
2699
2843
  }
2700
- return report;
2701
- } catch {
2702
- return null;
2844
+ return {
2845
+ report,
2846
+ diagnostic: {
2847
+ attempted: true,
2848
+ outcome: "matched",
2849
+ transport: this.summarizeTransportForDebug(transport)
2850
+ }
2851
+ };
2852
+ } catch (error) {
2853
+ return {
2854
+ report: null,
2855
+ diagnostic: {
2856
+ attempted: true,
2857
+ outcome: "fetch_error",
2858
+ transport: this.summarizeTransportForDebug(transport),
2859
+ error: error instanceof Error ? error.message : String(error)
2860
+ }
2861
+ };
2703
2862
  } finally {
2704
2863
  if (timeoutId) {
2705
2864
  clearTimeout(timeoutId);
@@ -3825,13 +3984,7 @@ var SocketController = class _SocketController {
3825
3984
  ws.on(
3826
3985
  "status_check",
3827
3986
  (ctx, callback) => {
3828
- CadenzaService.createEphemeralMetaTask(
3829
- "Resolve status check",
3830
- callback,
3831
- "Resolves a status check request",
3832
- { register: false }
3833
- ).doAfter(CadenzaService.serviceRegistry.getStatusTask);
3834
- CadenzaService.emit("meta.socket.status_check_requested", ctx);
3987
+ callback(CadenzaService.serviceRegistry.resolveLocalStatusCheck(ctx));
3835
3988
  }
3836
3989
  );
3837
3990
  ws.on("disconnect", () => {