service-bridge 1.0.10-dev.23 → 1.0.10-dev.26
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.js +70 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -90,7 +90,27 @@ class ServiceBridgeError extends Error {
|
|
|
90
90
|
this.operation = opts.operation;
|
|
91
91
|
this.severity = opts.severity;
|
|
92
92
|
this.retryable = opts.severity === "retriable";
|
|
93
|
-
this
|
|
93
|
+
Object.defineProperty(this, "cause", {
|
|
94
|
+
value: opts.cause,
|
|
95
|
+
writable: true,
|
|
96
|
+
enumerable: false,
|
|
97
|
+
configurable: true
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
toString() {
|
|
101
|
+
return `ServiceBridgeError [${this.severity}]: ${this.message} (${this.operation})`;
|
|
102
|
+
}
|
|
103
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
104
|
+
const lines = [
|
|
105
|
+
`ServiceBridgeError [${this.severity}]`,
|
|
106
|
+
` operation: ${this.operation}`,
|
|
107
|
+
` message: ${this.message}`
|
|
108
|
+
];
|
|
109
|
+
if (this.code !== undefined) {
|
|
110
|
+
lines.push(` code: ${this.code}`);
|
|
111
|
+
}
|
|
112
|
+
return lines.join(`
|
|
113
|
+
`);
|
|
94
114
|
}
|
|
95
115
|
}
|
|
96
116
|
function containsValue(values, value) {
|
|
@@ -214,7 +234,14 @@ function normalizeServiceError(err, operation, component = "control-plane") {
|
|
|
214
234
|
}
|
|
215
235
|
const grpcErr = err;
|
|
216
236
|
const code = typeof grpcErr?.code === "number" ? grpcErr.code : undefined;
|
|
217
|
-
const
|
|
237
|
+
const details = typeof grpcErr?.details === "string" && grpcErr.details.trim() ? grpcErr.details.trim() : undefined;
|
|
238
|
+
const rawMsg = (() => {
|
|
239
|
+
const m = typeof grpcErr?.message === "string" && grpcErr.message ? grpcErr.message : err instanceof Error ? err.message : String(err);
|
|
240
|
+
return m.replace(/^\d+\s+[A-Z_]+:\s*/, "").trim() || m;
|
|
241
|
+
})();
|
|
242
|
+
const base = friendlyGrpcMessage(code, details ?? rawMsg);
|
|
243
|
+
const appendDetails = details && (code === grpc.status.INTERNAL || code === grpc.status.UNKNOWN || code === undefined);
|
|
244
|
+
const message = appendDetails ? `${base}: ${details}` : base;
|
|
218
245
|
return new ServiceBridgeError({
|
|
219
246
|
message,
|
|
220
247
|
code,
|
|
@@ -225,6 +252,8 @@ function normalizeServiceError(err, operation, component = "control-plane") {
|
|
|
225
252
|
});
|
|
226
253
|
}
|
|
227
254
|
function friendlyGrpcMessage(code, rawMessage) {
|
|
255
|
+
if (code === undefined)
|
|
256
|
+
return rawMessage || "unknown error";
|
|
228
257
|
switch (code) {
|
|
229
258
|
case grpc.status.UNAVAILABLE:
|
|
230
259
|
return "control plane unavailable";
|
|
@@ -246,12 +275,14 @@ function friendlyGrpcMessage(code, rawMessage) {
|
|
|
246
275
|
return "request cancelled";
|
|
247
276
|
case grpc.status.UNIMPLEMENTED:
|
|
248
277
|
return "operation not supported by control plane";
|
|
278
|
+
case grpc.status.UNKNOWN:
|
|
279
|
+
return "unknown error from control plane";
|
|
249
280
|
default:
|
|
250
281
|
return rawMessage || "unknown error";
|
|
251
282
|
}
|
|
252
283
|
}
|
|
253
284
|
function friendlySDKMessage(operation, err) {
|
|
254
|
-
const base =
|
|
285
|
+
const base = err.message;
|
|
255
286
|
switch (operation) {
|
|
256
287
|
case "open-worker-session":
|
|
257
288
|
case "worker-session":
|
|
@@ -268,7 +299,7 @@ function friendlySDKMessage(operation, err) {
|
|
|
268
299
|
return `offline queue flush failed: ${base}`;
|
|
269
300
|
case "flush-on-ready":
|
|
270
301
|
case "flush-on-restore":
|
|
271
|
-
return `
|
|
302
|
+
return `offline queue flush failed: ${base}`;
|
|
272
303
|
case "report-call-start":
|
|
273
304
|
case "report-call":
|
|
274
305
|
return `call report failed: ${base}`;
|
|
@@ -884,12 +915,15 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
884
915
|
onlineRestoreTimer = null;
|
|
885
916
|
if (!stopped) {
|
|
886
917
|
isOnline = true;
|
|
918
|
+
const queueLen = offlineQueue.length;
|
|
919
|
+
console.info(`[servicebridge] reconnected to runtime${queueLen > 0 ? ` — flushing ${queueLen} queued operation(s)` : ""}`);
|
|
887
920
|
flushQueue().catch((err) => {
|
|
888
921
|
if (isConnectionError(err))
|
|
889
922
|
scheduleOnlineRestore();
|
|
890
923
|
else
|
|
891
924
|
reportSDKError("flush-on-restore", err);
|
|
892
925
|
});
|
|
926
|
+
scheduleNextHeartbeat(100);
|
|
893
927
|
}
|
|
894
928
|
}, 2000);
|
|
895
929
|
}
|
|
@@ -924,6 +958,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
924
958
|
attempt
|
|
925
959
|
}).catch((err) => {
|
|
926
960
|
if (isConnectionError(err)) {
|
|
961
|
+
if (isOnline) {
|
|
962
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
963
|
+
}
|
|
927
964
|
isOnline = false;
|
|
928
965
|
scheduleOnlineRestore();
|
|
929
966
|
enqueueOffline({
|
|
@@ -972,6 +1009,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
972
1009
|
error
|
|
973
1010
|
}).catch((err) => {
|
|
974
1011
|
if (isConnectionError(err)) {
|
|
1012
|
+
if (isOnline) {
|
|
1013
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1014
|
+
}
|
|
975
1015
|
isOnline = false;
|
|
976
1016
|
scheduleOnlineRestore();
|
|
977
1017
|
enqueueOffline({
|
|
@@ -993,6 +1033,10 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
993
1033
|
});
|
|
994
1034
|
}
|
|
995
1035
|
async function flushQueue() {
|
|
1036
|
+
if (offlineQueue.length === 0)
|
|
1037
|
+
return;
|
|
1038
|
+
const snapshot = offlineQueue.slice();
|
|
1039
|
+
let flushed = 0;
|
|
996
1040
|
while (offlineQueue.length > 0 && isOnline) {
|
|
997
1041
|
const op = offlineQueue[0];
|
|
998
1042
|
try {
|
|
@@ -1036,8 +1080,12 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1036
1080
|
await sendReportCall(op);
|
|
1037
1081
|
}
|
|
1038
1082
|
offlineQueue.shift();
|
|
1083
|
+
flushed++;
|
|
1039
1084
|
} catch (err) {
|
|
1040
1085
|
if (isConnectionError(err)) {
|
|
1086
|
+
if (isOnline) {
|
|
1087
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1088
|
+
}
|
|
1041
1089
|
isOnline = false;
|
|
1042
1090
|
scheduleOnlineRestore();
|
|
1043
1091
|
break;
|
|
@@ -1046,6 +1094,18 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1046
1094
|
break;
|
|
1047
1095
|
}
|
|
1048
1096
|
}
|
|
1097
|
+
if (flushed > 0) {
|
|
1098
|
+
const remaining = offlineQueue.length;
|
|
1099
|
+
const sentOps = snapshot.slice(0, flushed);
|
|
1100
|
+
console.info(`[servicebridge] flushed ${flushed}/${snapshot.length} queued operation(s) to runtime` + ` (${formatQueueSummary(sentOps)})` + (remaining > 0 ? ` — ${remaining} still queued` : ""));
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
function formatQueueSummary(ops) {
|
|
1104
|
+
const counts = {};
|
|
1105
|
+
for (const op of ops) {
|
|
1106
|
+
counts[op.type] = (counts[op.type] ?? 0) + 1;
|
|
1107
|
+
}
|
|
1108
|
+
return Object.entries(counts).map(([type, n]) => `${n} ${type}`).join(", ");
|
|
1049
1109
|
}
|
|
1050
1110
|
function requirePeerCN(call, allowedCallers, isDeliver) {
|
|
1051
1111
|
const peerCN = extractPeerCN(call);
|
|
@@ -1192,6 +1252,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1192
1252
|
}
|
|
1193
1253
|
} catch (err) {
|
|
1194
1254
|
if (isConnectionError(err)) {
|
|
1255
|
+
if (isOnline) {
|
|
1256
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1257
|
+
}
|
|
1195
1258
|
isOnline = false;
|
|
1196
1259
|
scheduleOnlineRestore();
|
|
1197
1260
|
} else if (isRegistryResyncRequiredError(err)) {
|
|
@@ -1716,7 +1779,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1716
1779
|
closeWorkerSession();
|
|
1717
1780
|
serveState = null;
|
|
1718
1781
|
shutdownWorkerServerGracefully();
|
|
1719
|
-
|
|
1782
|
+
const fatal = normalizeServiceError(err, "serve");
|
|
1783
|
+
console.error(`[servicebridge] startup failed: ${fatal.message}`);
|
|
1784
|
+
throw fatal;
|
|
1720
1785
|
}
|
|
1721
1786
|
},
|
|
1722
1787
|
stop() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "service-bridge",
|
|
3
|
-
"version": "1.0.10-dev.
|
|
3
|
+
"version": "1.0.10-dev.26",
|
|
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": [
|