service-bridge 1.0.9-dev.22 → 1.0.10-dev.23

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 (2) hide show
  1. package/dist/index.js +119 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -224,13 +224,70 @@ function normalizeServiceError(err, operation, component = "control-plane") {
224
224
  cause: err
225
225
  });
226
226
  }
227
+ function friendlyGrpcMessage(code, rawMessage) {
228
+ switch (code) {
229
+ case grpc.status.UNAVAILABLE:
230
+ return "control plane unavailable";
231
+ case grpc.status.DEADLINE_EXCEEDED:
232
+ return "request timed out";
233
+ case grpc.status.UNAUTHENTICATED:
234
+ return "authentication failed — check service key";
235
+ case grpc.status.PERMISSION_DENIED:
236
+ return "permission denied — check service key";
237
+ case grpc.status.RESOURCE_EXHAUSTED:
238
+ return "rate limit exceeded";
239
+ case grpc.status.NOT_FOUND:
240
+ return "resource not found";
241
+ case grpc.status.INTERNAL:
242
+ return "internal server error";
243
+ case grpc.status.FAILED_PRECONDITION:
244
+ return "precondition failed";
245
+ case grpc.status.CANCELLED:
246
+ return "request cancelled";
247
+ case grpc.status.UNIMPLEMENTED:
248
+ return "operation not supported by control plane";
249
+ default:
250
+ return rawMessage || "unknown error";
251
+ }
252
+ }
253
+ function friendlySDKMessage(operation, err) {
254
+ const base = friendlyGrpcMessage(err.code, err.message);
255
+ switch (operation) {
256
+ case "open-worker-session":
257
+ case "worker-session":
258
+ return err.severity === "retriable" ? `${base} — waiting for reconnect` : `worker session error: ${base}`;
259
+ case "worker-session-end":
260
+ return `worker session cleanup: ${base}`;
261
+ case "worker-session-command":
262
+ return `worker command error: ${base}`;
263
+ case "heartbeat":
264
+ return `heartbeat failed: ${base}`;
265
+ case "http-heartbeat":
266
+ return `HTTP heartbeat failed: ${base}`;
267
+ case "flush-offline-queue":
268
+ return `offline queue flush failed: ${base}`;
269
+ case "flush-on-ready":
270
+ case "flush-on-restore":
271
+ return `log flush failed: ${base}`;
272
+ case "report-call-start":
273
+ case "report-call":
274
+ return `call report failed: ${base}`;
275
+ case "worker-force-shutdown":
276
+ case "worker-try-shutdown":
277
+ return `worker shutdown error: ${base}`;
278
+ case "close-control-plane-client":
279
+ return `control plane disconnect: ${base}`;
280
+ default:
281
+ return `${operation}: ${base}`;
282
+ }
283
+ }
227
284
  function reportSDKError(operation, err, component = "sdk") {
228
285
  const normalized = normalizeServiceError(err, operation, component);
229
- const message = `[servicebridge] ${normalized.component}.${normalized.operation}: ${normalized.message}`;
286
+ const friendly = friendlySDKMessage(operation, normalized);
230
287
  if (normalized.severity === "fatal") {
231
- console.error(message, err);
288
+ console.error(`[servicebridge] ${friendly}`);
232
289
  } else {
233
- console.warn(message, err);
290
+ console.warn(`[servicebridge] ${friendly}`);
234
291
  }
235
292
  return normalized;
236
293
  }
@@ -551,7 +608,30 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
551
608
  md.add("x-caller-service", service);
552
609
  return md;
553
610
  }
611
+ function sessionSend(msg) {
612
+ if (!workerSessionStream)
613
+ return false;
614
+ try {
615
+ workerSessionStream.write(msg);
616
+ return true;
617
+ } catch {
618
+ return false;
619
+ }
620
+ }
554
621
  async function sendReportCallStart(op) {
622
+ if (sessionSend({
623
+ telemetry_start: {
624
+ trace_id: op.traceId,
625
+ span_id: op.spanId,
626
+ parent_span_id: op.parentSpanId,
627
+ fn: op.fn,
628
+ started_at: String(op.startedAt),
629
+ input: op.inputBuf,
630
+ attempt: op.attempt
631
+ }
632
+ })) {
633
+ return;
634
+ }
555
635
  await new Promise((resolve, reject) => {
556
636
  stub.ReportCallStart({
557
637
  trace_id: op.traceId,
@@ -567,6 +647,22 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
567
647
  });
568
648
  }
569
649
  async function sendReportCall(op) {
650
+ if (sessionSend({
651
+ telemetry_finish: {
652
+ trace_id: op.traceId,
653
+ span_id: op.spanId,
654
+ fn: op.fn,
655
+ started_at: String(op.startedAt),
656
+ duration_ms: String(op.durationMs),
657
+ success: op.success,
658
+ error: op.error ?? "",
659
+ input: op.inputBuf,
660
+ output: op.outputBuf ?? Buffer.alloc(0),
661
+ attempt: op.attempt
662
+ }
663
+ })) {
664
+ return;
665
+ }
570
666
  await new Promise((resolve, reject) => {
571
667
  stub.ReportCall({
572
668
  trace_id: op.traceId,
@@ -598,6 +694,8 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
598
694
  clearTimeout(logFlushTimer);
599
695
  logFlushTimer = null;
600
696
  }
697
+ if (sessionSend({ telemetry_log: { entries } }))
698
+ return;
601
699
  stub.ReportLog({ entries }, meta, unaryDeadlineOptions(), () => {});
602
700
  }
603
701
  function pushLog(level, msg, attrs) {
@@ -972,6 +1070,17 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
972
1070
  return;
973
1071
  const state = serveState;
974
1072
  const metrics = getProcessMetrics();
1073
+ const hbMsg = {
1074
+ endpoint: state.endpoint,
1075
+ group_names: [...registeredGroups],
1076
+ function_names: [...fnHandlers.keys()]
1077
+ };
1078
+ if (metrics.cpuPercent != null)
1079
+ hbMsg.cpu_percent = metrics.cpuPercent;
1080
+ if (metrics.ramMb != null)
1081
+ hbMsg.ram_mb = metrics.ramMb;
1082
+ if (sessionSend({ heartbeat: hbMsg }))
1083
+ return;
975
1084
  const req = {
976
1085
  service_name: service,
977
1086
  instance_id: state.instanceId,
@@ -989,6 +1098,8 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
989
1098
  });
990
1099
  }
991
1100
  async function sendHttpHeartbeat(instanceId) {
1101
+ if (sessionSend({ http_heartbeat: {} }))
1102
+ return;
992
1103
  await new Promise((resolve, reject) => {
993
1104
  stub.HeartbeatHttpEndpoint({ service_name: service, instance_id: instanceId }, meta, unaryDeadlineOptions(), (err, res) => {
994
1105
  if (err) {
@@ -1110,12 +1221,12 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
1110
1221
  const append = (data, key = "default") => {
1111
1222
  if (!isOnline || !runId)
1112
1223
  return Promise.resolve();
1224
+ const dataBuf = Buffer.from(JSON.stringify(data));
1225
+ if (sessionSend({ append_stream: { run_id: runId, key, data: dataBuf } })) {
1226
+ return Promise.resolve();
1227
+ }
1113
1228
  return new Promise((resolve, reject) => {
1114
- stub.AppendStream({
1115
- run_id: runId,
1116
- key,
1117
- data: Buffer.from(JSON.stringify(data))
1118
- }, meta, unaryDeadlineOptions(), (err) => err ? reject(normalizeServiceError(err, `append-stream:${runId}`)) : resolve());
1229
+ stub.AppendStream({ run_id: runId, key, data: dataBuf }, meta, unaryDeadlineOptions(), (err) => err ? reject(normalizeServiceError(err, `append-stream:${runId}`)) : resolve());
1119
1230
  });
1120
1231
  };
1121
1232
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "service-bridge",
3
- "version": "1.0.9-dev.22",
3
+ "version": "1.0.10-dev.23",
4
4
  "type": "module",
5
5
  "description": "ServiceBridge SDK for Node.js — production-ready RPC, durable events, workflows, jobs, and distributed tracing. One Go runtime + PostgreSQL replaces Istio, RabbitMQ, Temporal, and Jaeger.",
6
6
  "keywords": [