@rotorsoft/act 0.20.0 → 0.21.0
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/README.md +16 -57
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +2 -2
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/InMemoryStore.d.ts +15 -15
- package/dist/@types/adapters/InMemoryStore.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +4 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +48 -47
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +0 -13
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/index.cjs +121 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +121 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -391,41 +391,54 @@ var InMemoryStore = class {
|
|
|
391
391
|
});
|
|
392
392
|
}
|
|
393
393
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
* @param
|
|
397
|
-
* @
|
|
394
|
+
* Atomically discovers and leases streams for processing.
|
|
395
|
+
* Fuses poll + lease into a single operation.
|
|
396
|
+
* @param lagging - Max streams from lagging frontier.
|
|
397
|
+
* @param leading - Max streams from leading frontier.
|
|
398
|
+
* @param by - Lease holder identifier.
|
|
399
|
+
* @param millis - Lease duration in milliseconds.
|
|
400
|
+
* @returns Granted leases.
|
|
398
401
|
*/
|
|
399
|
-
async
|
|
402
|
+
async claim(lagging, leading, by, millis) {
|
|
400
403
|
await sleep();
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
404
|
+
const available = [...this._streams.values()].filter((s) => s.is_avaliable);
|
|
405
|
+
const lag = available.sort((a, b) => a.at - b.at).slice(0, lagging).map((s) => ({
|
|
406
|
+
stream: s.stream,
|
|
407
|
+
source: s.source,
|
|
408
|
+
at: s.at,
|
|
405
409
|
lagging: true
|
|
406
410
|
}));
|
|
407
|
-
const
|
|
408
|
-
stream,
|
|
409
|
-
source,
|
|
410
|
-
at,
|
|
411
|
+
const lead = available.sort((a, b) => b.at - a.at).slice(0, leading).map((s) => ({
|
|
412
|
+
stream: s.stream,
|
|
413
|
+
source: s.source,
|
|
414
|
+
at: s.at,
|
|
411
415
|
lagging: false
|
|
412
416
|
}));
|
|
413
|
-
|
|
417
|
+
const seen = /* @__PURE__ */ new Set();
|
|
418
|
+
const combined = [...lag, ...lead].filter((p) => {
|
|
419
|
+
if (seen.has(p.stream)) return false;
|
|
420
|
+
seen.add(p.stream);
|
|
421
|
+
return true;
|
|
422
|
+
});
|
|
423
|
+
return combined.map(
|
|
424
|
+
(p) => this._streams.get(p.stream)?.lease({ ...p, by, retry: 0 }, millis)
|
|
425
|
+
).filter((l) => !!l);
|
|
414
426
|
}
|
|
415
427
|
/**
|
|
416
|
-
*
|
|
417
|
-
* @param
|
|
418
|
-
* @
|
|
419
|
-
* @returns Granted leases.
|
|
428
|
+
* Registers streams for event processing.
|
|
429
|
+
* @param streams - Streams to register with optional source.
|
|
430
|
+
* @returns Number of newly registered streams.
|
|
420
431
|
*/
|
|
421
|
-
async
|
|
432
|
+
async subscribe(streams) {
|
|
422
433
|
await sleep();
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
434
|
+
let count = 0;
|
|
435
|
+
for (const { stream, source } of streams) {
|
|
436
|
+
if (!this._streams.has(stream)) {
|
|
437
|
+
this._streams.set(stream, new InMemoryStream(stream, source));
|
|
438
|
+
count++;
|
|
426
439
|
}
|
|
427
|
-
|
|
428
|
-
|
|
440
|
+
}
|
|
441
|
+
return count;
|
|
429
442
|
}
|
|
430
443
|
/**
|
|
431
444
|
* Acknowledge completion of processing for leased streams.
|
|
@@ -509,8 +522,8 @@ function build_tracer(logLevel2) {
|
|
|
509
522
|
);
|
|
510
523
|
logger.trace(data, "\u26A1\uFE0F fetch");
|
|
511
524
|
},
|
|
512
|
-
correlated: (
|
|
513
|
-
const data =
|
|
525
|
+
correlated: (streams) => {
|
|
526
|
+
const data = streams.map(({ stream }) => stream).join(" ");
|
|
514
527
|
logger.trace(`\u26A1\uFE0F correlate ${data}`);
|
|
515
528
|
},
|
|
516
529
|
leased: (leases) => {
|
|
@@ -1029,9 +1042,16 @@ var Act = class {
|
|
|
1029
1042
|
this._drain_locked = true;
|
|
1030
1043
|
const lagging = Math.ceil(streamLimit * this._drain_lag2lead_ratio);
|
|
1031
1044
|
const leading = streamLimit - lagging;
|
|
1032
|
-
const
|
|
1045
|
+
const leased = await store().claim(
|
|
1046
|
+
lagging,
|
|
1047
|
+
leading,
|
|
1048
|
+
randomUUID2(),
|
|
1049
|
+
leaseMillis
|
|
1050
|
+
);
|
|
1051
|
+
if (!leased.length)
|
|
1052
|
+
return { fetched: [], leased: [], acked: [], blocked: [] };
|
|
1033
1053
|
const fetched = await Promise.all(
|
|
1034
|
-
|
|
1054
|
+
leased.map(async ({ stream, source, at, lagging: lagging2 }) => {
|
|
1035
1055
|
const events = await this.query_array({
|
|
1036
1056
|
stream: source,
|
|
1037
1057
|
after: at,
|
|
@@ -1040,71 +1060,60 @@ var Act = class {
|
|
|
1040
1060
|
return { stream, source, at, lagging: lagging2, events };
|
|
1041
1061
|
})
|
|
1042
1062
|
);
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
}).map((reaction) => ({ ...reaction, event }));
|
|
1058
|
-
});
|
|
1059
|
-
leases.set(stream, {
|
|
1060
|
-
lease: {
|
|
1061
|
-
stream,
|
|
1062
|
-
by: randomUUID2(),
|
|
1063
|
-
at: events.at(-1)?.id || fetch_window_at,
|
|
1064
|
-
// ff when no matching events
|
|
1065
|
-
retry: 0,
|
|
1066
|
-
lagging: lagging2
|
|
1067
|
-
},
|
|
1068
|
-
payloads
|
|
1069
|
-
});
|
|
1063
|
+
tracer.fetched(fetched);
|
|
1064
|
+
const payloadsMap = /* @__PURE__ */ new Map();
|
|
1065
|
+
const fetch_window_at = fetched.reduce(
|
|
1066
|
+
(max, { at, events }) => Math.max(max, events.at(-1)?.id || at),
|
|
1067
|
+
0
|
|
1068
|
+
);
|
|
1069
|
+
fetched.forEach(({ stream, events }) => {
|
|
1070
|
+
const payloads = events.flatMap((event) => {
|
|
1071
|
+
const register = this.registry.events[event.name];
|
|
1072
|
+
if (!register) return [];
|
|
1073
|
+
return [...register.reactions.values()].filter((reaction) => {
|
|
1074
|
+
const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
1075
|
+
return resolved && resolved.target === stream;
|
|
1076
|
+
}).map((reaction) => ({ ...reaction, event }));
|
|
1070
1077
|
});
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1078
|
+
payloadsMap.set(stream, payloads);
|
|
1079
|
+
});
|
|
1080
|
+
tracer.leased(leased);
|
|
1081
|
+
const handled = await Promise.all(
|
|
1082
|
+
leased.map((lease) => {
|
|
1083
|
+
const streamFetch = fetched.find((f) => f.stream === lease.stream);
|
|
1084
|
+
const at = streamFetch?.events.at(-1)?.id || fetch_window_at;
|
|
1085
|
+
return this.handle(
|
|
1086
|
+
{ ...lease, at },
|
|
1087
|
+
payloadsMap.get(lease.stream) || []
|
|
1088
|
+
);
|
|
1089
|
+
})
|
|
1090
|
+
);
|
|
1091
|
+
const [lagging_handled, leading_handled] = handled.reduce(
|
|
1092
|
+
([lagging_handled2, leading_handled2], { lease, handled: handled2 }) => [
|
|
1093
|
+
lagging_handled2 + (lease.lagging ? handled2 : 0),
|
|
1094
|
+
leading_handled2 + (lease.lagging ? 0 : handled2)
|
|
1095
|
+
],
|
|
1096
|
+
[0, 0]
|
|
1097
|
+
);
|
|
1098
|
+
const lagging_avg = lagging > 0 ? lagging_handled / lagging : 0;
|
|
1099
|
+
const leading_avg = leading > 0 ? leading_handled / leading : 0;
|
|
1100
|
+
const total = lagging_avg + leading_avg;
|
|
1101
|
+
this._drain_lag2lead_ratio = total > 0 ? Math.max(0.2, Math.min(0.8, lagging_avg / total)) : 0.5;
|
|
1102
|
+
const acked = await store().ack(
|
|
1103
|
+
handled.filter(({ error }) => !error).map(({ at, lease }) => ({ ...lease, at }))
|
|
1104
|
+
);
|
|
1105
|
+
if (acked.length) {
|
|
1106
|
+
tracer.acked(acked);
|
|
1107
|
+
this.emit("acked", acked);
|
|
1108
|
+
}
|
|
1109
|
+
const blocked = await store().block(
|
|
1110
|
+
handled.filter(({ block }) => block).map(({ lease, error }) => ({ ...lease, error }))
|
|
1111
|
+
);
|
|
1112
|
+
if (blocked.length) {
|
|
1113
|
+
tracer.blocked(blocked);
|
|
1114
|
+
this.emit("blocked", blocked);
|
|
1107
1115
|
}
|
|
1116
|
+
return { fetched, leased, acked, blocked };
|
|
1108
1117
|
} catch (error) {
|
|
1109
1118
|
logger.error(error);
|
|
1110
1119
|
} finally {
|
|
@@ -1167,26 +1176,31 @@ var Act = class {
|
|
|
1167
1176
|
if (register) {
|
|
1168
1177
|
for (const reaction of register.reactions.values()) {
|
|
1169
1178
|
const resolved = typeof reaction.resolver === "function" ? reaction.resolver(event) : reaction.resolver;
|
|
1170
|
-
|
|
1179
|
+
if (resolved) {
|
|
1180
|
+
const entry = correlated.get(resolved.target) || {
|
|
1181
|
+
source: resolved.source,
|
|
1182
|
+
payloads: []
|
|
1183
|
+
};
|
|
1184
|
+
entry.payloads.push({
|
|
1185
|
+
...reaction,
|
|
1186
|
+
source: resolved.source,
|
|
1187
|
+
event
|
|
1188
|
+
});
|
|
1189
|
+
correlated.set(resolved.target, entry);
|
|
1190
|
+
}
|
|
1171
1191
|
}
|
|
1172
1192
|
}
|
|
1173
1193
|
}, query);
|
|
1174
1194
|
if (correlated.size) {
|
|
1175
|
-
const
|
|
1195
|
+
const streams = [...correlated.entries()].map(([stream, { source }]) => ({
|
|
1176
1196
|
stream,
|
|
1177
|
-
|
|
1178
|
-
source: payloads.find((p) => p.source)?.source || void 0,
|
|
1179
|
-
by: randomUUID2(),
|
|
1180
|
-
at: 0,
|
|
1181
|
-
retry: 0,
|
|
1182
|
-
lagging: true,
|
|
1183
|
-
payloads
|
|
1197
|
+
source
|
|
1184
1198
|
}));
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
return {
|
|
1199
|
+
const subscribed = await store().subscribe(streams);
|
|
1200
|
+
subscribed && tracer.correlated(streams);
|
|
1201
|
+
return { subscribed, last_id };
|
|
1188
1202
|
}
|
|
1189
|
-
return {
|
|
1203
|
+
return { subscribed: 0, last_id };
|
|
1190
1204
|
}
|
|
1191
1205
|
/**
|
|
1192
1206
|
* Starts automatic periodic correlation worker for discovering new streams.
|
|
@@ -1250,7 +1264,7 @@ var Act = class {
|
|
|
1250
1264
|
this._correlation_timer = setInterval(
|
|
1251
1265
|
() => this.correlate({ ...query, after, limit }).then((result) => {
|
|
1252
1266
|
after = result.last_id;
|
|
1253
|
-
if (callback && result.
|
|
1267
|
+
if (callback && result.subscribed) callback(result.subscribed);
|
|
1254
1268
|
}).catch(console.error),
|
|
1255
1269
|
frequency
|
|
1256
1270
|
);
|
|
@@ -1334,8 +1348,8 @@ var Act = class {
|
|
|
1334
1348
|
(async () => {
|
|
1335
1349
|
let lastDrain;
|
|
1336
1350
|
for (let i = 0; i < maxPasses; i++) {
|
|
1337
|
-
const {
|
|
1338
|
-
if (
|
|
1351
|
+
const { subscribed } = await this.correlate(correlateQuery);
|
|
1352
|
+
if (subscribed === 0 && i > 0) break;
|
|
1339
1353
|
lastDrain = await this.drain(drainOptions);
|
|
1340
1354
|
if (!lastDrain.acked.length && !lastDrain.blocked.length) break;
|
|
1341
1355
|
}
|