@rotorsoft/act 0.15.0 → 0.16.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 +12 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +52 -36
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +17 -1
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/index.cjs +84 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +84 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -697,13 +697,16 @@ var Act = class {
|
|
|
697
697
|
dispose(() => {
|
|
698
698
|
this._emitter.removeAllListeners();
|
|
699
699
|
this.stop_correlations();
|
|
700
|
+
this.stop_settling();
|
|
700
701
|
return Promise.resolve();
|
|
701
702
|
});
|
|
702
703
|
}
|
|
703
704
|
_emitter = new EventEmitter();
|
|
704
705
|
_drain_locked = false;
|
|
705
706
|
_drain_lag2lead_ratio = 0.5;
|
|
706
|
-
|
|
707
|
+
_correlation_timer = void 0;
|
|
708
|
+
_settle_timer = void 0;
|
|
709
|
+
_settling = false;
|
|
707
710
|
emit(event, args) {
|
|
708
711
|
return this._emitter.emit(event, args);
|
|
709
712
|
}
|
|
@@ -953,7 +956,7 @@ var Act = class {
|
|
|
953
956
|
/**
|
|
954
957
|
* Processes pending reactions by draining uncommitted events from the event store.
|
|
955
958
|
*
|
|
956
|
-
*
|
|
959
|
+
* Runs a single drain cycle:
|
|
957
960
|
* 1. Polls the store for streams with uncommitted events
|
|
958
961
|
* 2. Leases streams to prevent concurrent processing
|
|
959
962
|
* 3. Fetches events for each leased stream
|
|
@@ -963,7 +966,8 @@ var Act = class {
|
|
|
963
966
|
* Drain uses a dual-frontier strategy to balance processing of new streams (lagging)
|
|
964
967
|
* vs active streams (leading). The ratio adapts based on event pressure.
|
|
965
968
|
*
|
|
966
|
-
* Call
|
|
969
|
+
* Call `correlate()` before `drain()` to discover target streams. For a higher-level
|
|
970
|
+
* API that handles debouncing, correlation, and signaling automatically, use {@link settle}.
|
|
967
971
|
*
|
|
968
972
|
* @param options - Drain configuration options
|
|
969
973
|
* @param options.streamLimit - Maximum number of streams to process per cycle (default: 10)
|
|
@@ -971,46 +975,20 @@ var Act = class {
|
|
|
971
975
|
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
972
976
|
* @returns Drain statistics with fetched, leased, acked, and blocked counts
|
|
973
977
|
*
|
|
974
|
-
* @example
|
|
978
|
+
* @example In tests and scripts
|
|
975
979
|
* ```typescript
|
|
976
|
-
* // Process reactions after each action
|
|
977
980
|
* await app.do("createUser", target, payload);
|
|
981
|
+
* await app.correlate();
|
|
978
982
|
* await app.drain();
|
|
979
983
|
* ```
|
|
980
984
|
*
|
|
981
|
-
* @example
|
|
985
|
+
* @example In production, prefer settle()
|
|
982
986
|
* ```typescript
|
|
983
|
-
*
|
|
984
|
-
*
|
|
985
|
-
* const result = await app.drain({
|
|
986
|
-
* streamLimit: 20,
|
|
987
|
-
* eventLimit: 50
|
|
988
|
-
* });
|
|
989
|
-
* if (result.acked.length) {
|
|
990
|
-
* console.log(`Processed ${result.acked.length} streams`);
|
|
991
|
-
* }
|
|
992
|
-
* } catch (error) {
|
|
993
|
-
* console.error("Drain error:", error);
|
|
994
|
-
* }
|
|
995
|
-
* }, 5000); // Every 5 seconds
|
|
996
|
-
* ```
|
|
997
|
-
*
|
|
998
|
-
* @example With lifecycle listeners
|
|
999
|
-
* ```typescript
|
|
1000
|
-
* app.on("acked", (leases) => {
|
|
1001
|
-
* console.log(`Acknowledged ${leases.length} streams`);
|
|
1002
|
-
* });
|
|
1003
|
-
*
|
|
1004
|
-
* app.on("blocked", (blocked) => {
|
|
1005
|
-
* console.error(`Blocked ${blocked.length} streams due to errors`);
|
|
1006
|
-
* blocked.forEach(({ stream, error }) => {
|
|
1007
|
-
* console.error(`Stream ${stream}: ${error}`);
|
|
1008
|
-
* });
|
|
1009
|
-
* });
|
|
1010
|
-
*
|
|
1011
|
-
* await app.drain();
|
|
987
|
+
* await app.do("CreateItem", target, input);
|
|
988
|
+
* app.settle(); // debounced correlate→drain, emits "settled"
|
|
1012
989
|
* ```
|
|
1013
990
|
*
|
|
991
|
+
* @see {@link settle} for debounced correlate→drain with lifecycle events
|
|
1014
992
|
* @see {@link correlate} for dynamic stream discovery
|
|
1015
993
|
* @see {@link start_correlations} for automatic correlation
|
|
1016
994
|
*/
|
|
@@ -1239,10 +1217,10 @@ var Act = class {
|
|
|
1239
1217
|
* @see {@link stop_correlations} to stop the worker
|
|
1240
1218
|
*/
|
|
1241
1219
|
start_correlations(query = {}, frequency = 1e4, callback) {
|
|
1242
|
-
if (this.
|
|
1220
|
+
if (this._correlation_timer) return false;
|
|
1243
1221
|
const limit = query.limit || 100;
|
|
1244
1222
|
let after = query.after || -1;
|
|
1245
|
-
this.
|
|
1223
|
+
this._correlation_timer = setInterval(
|
|
1246
1224
|
() => this.correlate({ ...query, after, limit }).then((result) => {
|
|
1247
1225
|
after = result.last_id;
|
|
1248
1226
|
if (callback && result.leased.length) callback(result.leased);
|
|
@@ -1269,11 +1247,77 @@ var Act = class {
|
|
|
1269
1247
|
* @see {@link start_correlations}
|
|
1270
1248
|
*/
|
|
1271
1249
|
stop_correlations() {
|
|
1272
|
-
if (this.
|
|
1273
|
-
clearInterval(this.
|
|
1274
|
-
this.
|
|
1250
|
+
if (this._correlation_timer) {
|
|
1251
|
+
clearInterval(this._correlation_timer);
|
|
1252
|
+
this._correlation_timer = void 0;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Cancels any pending or active settle cycle.
|
|
1257
|
+
*
|
|
1258
|
+
* @see {@link settle}
|
|
1259
|
+
*/
|
|
1260
|
+
stop_settling() {
|
|
1261
|
+
if (this._settle_timer) {
|
|
1262
|
+
clearTimeout(this._settle_timer);
|
|
1263
|
+
this._settle_timer = void 0;
|
|
1275
1264
|
}
|
|
1276
1265
|
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Debounced, non-blocking correlate→drain cycle.
|
|
1268
|
+
*
|
|
1269
|
+
* Call this after `app.do()` to schedule a background drain. Multiple rapid
|
|
1270
|
+
* calls within the debounce window are coalesced into a single cycle. Runs
|
|
1271
|
+
* correlate→drain in a loop until the system reaches a consistent state,
|
|
1272
|
+
* then emits the `"settled"` lifecycle event.
|
|
1273
|
+
*
|
|
1274
|
+
* @param options - Settle configuration options
|
|
1275
|
+
* @param options.debounceMs - Debounce window in milliseconds (default: 10)
|
|
1276
|
+
* @param options.correlate - Query filter for correlation scans (default: `{ after: -1, limit: 100 }`)
|
|
1277
|
+
* @param options.maxPasses - Maximum correlate→drain loops (default: 5)
|
|
1278
|
+
* @param options.streamLimit - Maximum streams per drain cycle (default: 10)
|
|
1279
|
+
* @param options.eventLimit - Maximum events per stream (default: 10)
|
|
1280
|
+
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
1281
|
+
*
|
|
1282
|
+
* @example API mutations
|
|
1283
|
+
* ```typescript
|
|
1284
|
+
* await app.do("CreateItem", target, input);
|
|
1285
|
+
* app.settle(); // non-blocking, returns immediately
|
|
1286
|
+
*
|
|
1287
|
+
* app.on("settled", (drain) => {
|
|
1288
|
+
* // notify SSE clients, invalidate caches, etc.
|
|
1289
|
+
* });
|
|
1290
|
+
* ```
|
|
1291
|
+
*
|
|
1292
|
+
* @see {@link drain} for single synchronous drain cycles
|
|
1293
|
+
* @see {@link correlate} for manual correlation
|
|
1294
|
+
*/
|
|
1295
|
+
settle(options = {}) {
|
|
1296
|
+
const {
|
|
1297
|
+
debounceMs = 10,
|
|
1298
|
+
correlate: correlateQuery = { after: -1, limit: 100 },
|
|
1299
|
+
maxPasses = 5,
|
|
1300
|
+
...drainOptions
|
|
1301
|
+
} = options;
|
|
1302
|
+
if (this._settle_timer) clearTimeout(this._settle_timer);
|
|
1303
|
+
this._settle_timer = setTimeout(() => {
|
|
1304
|
+
this._settle_timer = void 0;
|
|
1305
|
+
if (this._settling) return;
|
|
1306
|
+
this._settling = true;
|
|
1307
|
+
(async () => {
|
|
1308
|
+
let lastDrain;
|
|
1309
|
+
for (let i = 0; i < maxPasses; i++) {
|
|
1310
|
+
const { leased } = await this.correlate(correlateQuery);
|
|
1311
|
+
if (leased.length === 0 && i > 0) break;
|
|
1312
|
+
lastDrain = await this.drain(drainOptions);
|
|
1313
|
+
if (!lastDrain.acked.length && !lastDrain.blocked.length) break;
|
|
1314
|
+
}
|
|
1315
|
+
if (lastDrain) this.emit("settled", lastDrain);
|
|
1316
|
+
})().catch((err) => logger.error(err)).finally(() => {
|
|
1317
|
+
this._settling = false;
|
|
1318
|
+
});
|
|
1319
|
+
}, debounceMs);
|
|
1320
|
+
}
|
|
1277
1321
|
};
|
|
1278
1322
|
|
|
1279
1323
|
// src/merge.ts
|