service-bridge 1.1.0-dev.27 → 1.1.1-dev.29
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 +92 -81
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -591,8 +591,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
591
591
|
const fnAliasMap = new Map;
|
|
592
592
|
const functionChannels = new Map;
|
|
593
593
|
let isOnline = false;
|
|
594
|
+
let isFlushing = false;
|
|
594
595
|
let stopped = false;
|
|
595
|
-
let
|
|
596
|
+
let isWatchingChannel = false;
|
|
596
597
|
const offlineQueue = [];
|
|
597
598
|
let workerServer = null;
|
|
598
599
|
let workerSessionStream = null;
|
|
@@ -900,36 +901,43 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
900
901
|
}
|
|
901
902
|
}
|
|
902
903
|
_controlReady.then(() => {
|
|
903
|
-
|
|
904
|
-
flushQueue().catch((err) => {
|
|
905
|
-
if (isConnectionError(err))
|
|
906
|
-
scheduleOnlineRestore();
|
|
907
|
-
else
|
|
908
|
-
reportSDKError("flush-on-ready", err);
|
|
909
|
-
});
|
|
904
|
+
watchChannelConnectivity();
|
|
910
905
|
}).catch(() => {});
|
|
911
|
-
function
|
|
912
|
-
|
|
906
|
+
function watchChannelConnectivity() {
|
|
907
|
+
isWatchingChannel = false;
|
|
908
|
+
if (stopped)
|
|
913
909
|
return;
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
910
|
+
const channel = stub.getChannel();
|
|
911
|
+
const state = channel.getConnectivityState(true);
|
|
912
|
+
if (state === grpc.connectivityState.READY) {
|
|
913
|
+
if (!isOnline) {
|
|
917
914
|
isOnline = true;
|
|
918
915
|
const queueLen = offlineQueue.length;
|
|
919
916
|
console.info(`[servicebridge] reconnected to runtime${queueLen > 0 ? ` — flushing ${queueLen} queued operation(s)` : ""}`);
|
|
920
|
-
flushQueue().
|
|
921
|
-
if (
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
917
|
+
flushQueue().then(() => {
|
|
918
|
+
if (isOnline)
|
|
919
|
+
scheduleNextHeartbeat(100);
|
|
920
|
+
}).catch((err) => {
|
|
921
|
+
reportSDKError("flush-on-restore", err);
|
|
925
922
|
});
|
|
926
|
-
scheduleNextHeartbeat(100);
|
|
927
923
|
}
|
|
928
|
-
}
|
|
924
|
+
} else if (state === grpc.connectivityState.TRANSIENT_FAILURE) {
|
|
925
|
+
if (isOnline) {
|
|
926
|
+
isOnline = false;
|
|
927
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
isWatchingChannel = true;
|
|
931
|
+
channel.watchConnectivityState(state, Infinity, watchChannelConnectivity);
|
|
932
|
+
}
|
|
933
|
+
function ensureChannelWatch() {
|
|
934
|
+
if (!isWatchingChannel && !stopped) {
|
|
935
|
+
watchChannelConnectivity();
|
|
936
|
+
}
|
|
929
937
|
}
|
|
930
938
|
function isConnectionError(e) {
|
|
931
939
|
const code = e?.code;
|
|
932
|
-
return code === grpc.status.UNAVAILABLE || code === grpc.status.UNKNOWN
|
|
940
|
+
return code === grpc.status.UNAVAILABLE || code === grpc.status.UNKNOWN;
|
|
933
941
|
}
|
|
934
942
|
function normalizeUnknownErrorMessage(error) {
|
|
935
943
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -962,7 +970,7 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
962
970
|
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
963
971
|
}
|
|
964
972
|
isOnline = false;
|
|
965
|
-
|
|
973
|
+
ensureChannelWatch();
|
|
966
974
|
enqueueOffline({
|
|
967
975
|
type: "reportCallStart",
|
|
968
976
|
traceId,
|
|
@@ -1013,7 +1021,7 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1013
1021
|
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1014
1022
|
}
|
|
1015
1023
|
isOnline = false;
|
|
1016
|
-
|
|
1024
|
+
ensureChannelWatch();
|
|
1017
1025
|
enqueueOffline({
|
|
1018
1026
|
type: "reportCall",
|
|
1019
1027
|
traceId,
|
|
@@ -1033,66 +1041,71 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1033
1041
|
});
|
|
1034
1042
|
}
|
|
1035
1043
|
async function flushQueue() {
|
|
1036
|
-
if (offlineQueue.length === 0)
|
|
1044
|
+
if (isFlushing || offlineQueue.length === 0)
|
|
1037
1045
|
return;
|
|
1046
|
+
isFlushing = true;
|
|
1038
1047
|
const snapshot = offlineQueue.slice();
|
|
1039
1048
|
let flushed = 0;
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1049
|
+
try {
|
|
1050
|
+
while (offlineQueue.length > 0 && isOnline) {
|
|
1051
|
+
const op = offlineQueue[0];
|
|
1052
|
+
try {
|
|
1053
|
+
if (op.type === "event") {
|
|
1054
|
+
await new Promise((res, rej) => {
|
|
1055
|
+
stub.Publish({
|
|
1056
|
+
topic: op.topic,
|
|
1057
|
+
payload: toJsonBuffer(op.payload),
|
|
1058
|
+
headers: toWireStringMap(op.opts?.headers),
|
|
1059
|
+
trace_id: op.opts?.traceId ?? "",
|
|
1060
|
+
parent_span_id: op.opts?.parentSpanId ?? "",
|
|
1061
|
+
producer_service: service,
|
|
1062
|
+
idempotency_key: op.opts?.idempotencyKey ?? ""
|
|
1063
|
+
}, meta, unaryDeadlineOptions(), (err) => err ? rej(err) : res());
|
|
1064
|
+
});
|
|
1065
|
+
} else if (op.type === "job") {
|
|
1066
|
+
await new Promise((res, rej) => {
|
|
1067
|
+
stub.RegisterJob({
|
|
1068
|
+
cron_expr: op.opts.cron ?? "",
|
|
1069
|
+
timezone: op.opts.timezone ?? "UTC",
|
|
1070
|
+
misfire_policy: op.opts.misfire ?? "fire_now",
|
|
1071
|
+
target_type: op.opts.via ?? "rpc",
|
|
1072
|
+
target_ref: op.target,
|
|
1073
|
+
delay_ms: op.opts.delay ?? 0,
|
|
1074
|
+
service_name: service,
|
|
1075
|
+
retry_policy_json: op.opts.retryPolicyJson ?? "{}"
|
|
1076
|
+
}, meta, unaryDeadlineOptions(), (err) => err ? rej(err) : res());
|
|
1077
|
+
});
|
|
1078
|
+
} else if (op.type === "workflow") {
|
|
1079
|
+
await new Promise((res, rej) => {
|
|
1080
|
+
stub.RegisterWorkflow({
|
|
1081
|
+
name: op.name,
|
|
1082
|
+
definition: JSON.stringify(op.steps),
|
|
1083
|
+
opts: op.opts ? JSON.stringify(op.opts) : "{}",
|
|
1084
|
+
service_name: service
|
|
1085
|
+
}, meta, unaryDeadlineOptions(), (err) => err ? rej(err) : res());
|
|
1086
|
+
});
|
|
1087
|
+
} else if (op.type === "reportCallStart") {
|
|
1088
|
+
await sendReportCallStart({ ...op });
|
|
1089
|
+
} else if (op.type === "reportCall") {
|
|
1090
|
+
await sendReportCall(op);
|
|
1091
|
+
}
|
|
1092
|
+
offlineQueue.shift();
|
|
1093
|
+
flushed++;
|
|
1094
|
+
} catch (err) {
|
|
1095
|
+
if (isConnectionError(err)) {
|
|
1096
|
+
if (isOnline) {
|
|
1097
|
+
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1098
|
+
}
|
|
1099
|
+
isOnline = false;
|
|
1100
|
+
ensureChannelWatch();
|
|
1101
|
+
break;
|
|
1088
1102
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
break;
|
|
1103
|
+
reportSDKError("flush-offline-queue", err);
|
|
1104
|
+
offlineQueue.shift();
|
|
1092
1105
|
}
|
|
1093
|
-
reportSDKError("flush-offline-queue", err);
|
|
1094
|
-
break;
|
|
1095
1106
|
}
|
|
1107
|
+
} finally {
|
|
1108
|
+
isFlushing = false;
|
|
1096
1109
|
}
|
|
1097
1110
|
if (flushed > 0) {
|
|
1098
1111
|
const remaining = offlineQueue.length;
|
|
@@ -1256,7 +1269,7 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1256
1269
|
console.warn("[servicebridge] lost connection to runtime — entering offline mode");
|
|
1257
1270
|
}
|
|
1258
1271
|
isOnline = false;
|
|
1259
|
-
|
|
1272
|
+
ensureChannelWatch();
|
|
1260
1273
|
} else if (isRegistryResyncRequiredError(err)) {
|
|
1261
1274
|
await syncRegistrations("heartbeat-resync");
|
|
1262
1275
|
} else {
|
|
@@ -1787,11 +1800,9 @@ function servicebridge(url, serviceKey, serviceOrOpts = {}, maybeGlobalOpts = {}
|
|
|
1787
1800
|
stop() {
|
|
1788
1801
|
stopped = true;
|
|
1789
1802
|
isOnline = false;
|
|
1790
|
-
|
|
1791
|
-
clearTimeout(onlineRestoreTimer);
|
|
1803
|
+
isWatchingChannel = false;
|
|
1792
1804
|
if (heartbeatTimer)
|
|
1793
1805
|
clearTimeout(heartbeatTimer);
|
|
1794
|
-
onlineRestoreTimer = null;
|
|
1795
1806
|
heartbeatTimer = null;
|
|
1796
1807
|
registeredGroups.clear();
|
|
1797
1808
|
closeWorkerSession();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "service-bridge",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-dev.29",
|
|
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": [
|