@rotorsoft/act 1.32.4 → 1.32.6
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/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +3 -3
- package/dist/@types/builders/merge.d.ts.map +1 -1
- package/dist/@types/internal/close-cycle.d.ts +7 -3
- package/dist/@types/internal/close-cycle.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/index.cjs +59 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +59 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1070,6 +1070,23 @@ async function run_close_cycle(targets, deps) {
|
|
|
1070
1070
|
const skipped = [];
|
|
1071
1071
|
const windowed_result = windowed.length ? await run_windowed_closes(windowed, deps, skipped) : /* @__PURE__ */ new Map();
|
|
1072
1072
|
if (!full.length) return { truncated: windowed_result, skipped };
|
|
1073
|
+
const truncated = await with_stream_locks(
|
|
1074
|
+
full.map((t) => t.stream),
|
|
1075
|
+
deps,
|
|
1076
|
+
() => run_full_closes(full, target_map, deps, skipped)
|
|
1077
|
+
);
|
|
1078
|
+
for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
|
|
1079
|
+
return { truncated, skipped };
|
|
1080
|
+
}
|
|
1081
|
+
function with_stream_locks(streams, deps, work) {
|
|
1082
|
+
const with_lock = deps.with_stream_lock ?? ((_stream, w) => w());
|
|
1083
|
+
return [...streams].sort().reduceRight(
|
|
1084
|
+
(inner, stream) => () => with_lock(stream, inner),
|
|
1085
|
+
work
|
|
1086
|
+
)();
|
|
1087
|
+
}
|
|
1088
|
+
async function run_full_closes(full, target_map, deps, skipped) {
|
|
1089
|
+
const none = /* @__PURE__ */ new Map();
|
|
1073
1090
|
const streams = full.map((t) => t.stream);
|
|
1074
1091
|
const stream_info = await scan_stream_heads(streams);
|
|
1075
1092
|
for (const target of full) {
|
|
@@ -1092,7 +1109,7 @@ async function run_close_cycle(targets, deps) {
|
|
|
1092
1109
|
deps.probe_page_size ?? SAFETY_PROBE_PAGE_SIZE,
|
|
1093
1110
|
deps.catch_up_correlation
|
|
1094
1111
|
);
|
|
1095
|
-
if (!safe.length) return
|
|
1112
|
+
if (!safe.length) return none;
|
|
1096
1113
|
const { guarded, guard_events } = await guard_with_tombstones(
|
|
1097
1114
|
safe,
|
|
1098
1115
|
stream_info,
|
|
@@ -1100,7 +1117,7 @@ async function run_close_cycle(targets, deps) {
|
|
|
1100
1117
|
deps.tombstone,
|
|
1101
1118
|
skipped
|
|
1102
1119
|
);
|
|
1103
|
-
if (!guarded.length) return
|
|
1120
|
+
if (!guarded.length) return none;
|
|
1104
1121
|
const seed_states = await load_restart_seeds(
|
|
1105
1122
|
guarded,
|
|
1106
1123
|
target_map,
|
|
@@ -1110,14 +1127,18 @@ async function run_close_cycle(targets, deps) {
|
|
|
1110
1127
|
deps.logger
|
|
1111
1128
|
);
|
|
1112
1129
|
await run_archive_callbacks(guarded, target_map);
|
|
1113
|
-
const
|
|
1130
|
+
const still_guarded = await heads_still_guarded(
|
|
1114
1131
|
guarded,
|
|
1132
|
+
guard_events,
|
|
1133
|
+
skipped
|
|
1134
|
+
);
|
|
1135
|
+
if (!still_guarded.length) return none;
|
|
1136
|
+
return truncate_and_warm_cache(
|
|
1137
|
+
still_guarded,
|
|
1115
1138
|
seed_states,
|
|
1116
1139
|
guard_events,
|
|
1117
1140
|
deps.correlation
|
|
1118
1141
|
);
|
|
1119
|
-
for (const [stream, entry] of windowed_result) truncated.set(stream, entry);
|
|
1120
|
-
return { truncated, skipped };
|
|
1121
1142
|
}
|
|
1122
1143
|
async function run_windowed_closes(windowed, deps, skipped) {
|
|
1123
1144
|
const checkpoint = deps.reactive_events_size > 0 ? await deps.catch_up_correlation(Number.MAX_SAFE_INTEGER) : -1;
|
|
@@ -1307,6 +1328,15 @@ async function run_archive_callbacks(guarded, target_map) {
|
|
|
1307
1328
|
if (archive_fn) await archive_fn();
|
|
1308
1329
|
}
|
|
1309
1330
|
}
|
|
1331
|
+
async function heads_still_guarded(guarded, guard_events, skipped) {
|
|
1332
|
+
const heads = await store().query_stats(guarded, {});
|
|
1333
|
+
return guarded.filter((stream) => {
|
|
1334
|
+
if (heads.get(stream)?.head.id === guard_events.get(stream).id)
|
|
1335
|
+
return true;
|
|
1336
|
+
skipped.push(stream);
|
|
1337
|
+
return false;
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1310
1340
|
async function truncate_and_warm_cache(guarded, seed_states, guard_events, correlation) {
|
|
1311
1341
|
const trunc_targets = guarded.map((stream) => {
|
|
1312
1342
|
const snapshot = seed_states.get(stream);
|
|
@@ -3050,6 +3080,7 @@ var DrainController = class {
|
|
|
3050
3080
|
if (!cycle) {
|
|
3051
3081
|
this._deps.breaker.passed();
|
|
3052
3082
|
this._armed = false;
|
|
3083
|
+
if (this._defer.size > 0) this._defer.schedule();
|
|
3053
3084
|
return EMPTY_DRAIN;
|
|
3054
3085
|
}
|
|
3055
3086
|
const { leased, fetched, handled, acked, blocked, closeable } = cycle;
|
|
@@ -3580,9 +3611,9 @@ var Act = class {
|
|
|
3580
3611
|
*/
|
|
3581
3612
|
_close_locks = /* @__PURE__ */ new Map();
|
|
3582
3613
|
/**
|
|
3583
|
-
* Run `work` under the per-stream close lock (#1222). Serializes
|
|
3584
|
-
*
|
|
3585
|
-
* different streams proceed in parallel.
|
|
3614
|
+
* Run `work` under the per-stream close lock (#1222). Serializes close
|
|
3615
|
+
* critical sections for the same stream (windowed prunes, and full closes
|
|
3616
|
+
* since #1738) while letting different streams proceed in parallel.
|
|
3586
3617
|
*/
|
|
3587
3618
|
_with_close_lock(stream, work) {
|
|
3588
3619
|
const prev = this._close_locks.get(stream) ?? Promise.resolve();
|
|
@@ -4950,23 +4981,29 @@ function base_type_name(zodType) {
|
|
|
4950
4981
|
return t.constructor.name;
|
|
4951
4982
|
}
|
|
4952
4983
|
function merge_schemas(existing, incoming, state_name) {
|
|
4953
|
-
if (existing
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4984
|
+
if (existing === incoming) return existing;
|
|
4985
|
+
const existing_object = as_object(existing, "existing", state_name);
|
|
4986
|
+
const incoming_object = as_object(incoming, "incoming", state_name);
|
|
4987
|
+
const existing_shape = existing_object.shape;
|
|
4988
|
+
const incoming_shape = incoming_object.shape;
|
|
4989
|
+
for (const key of Object.keys(incoming_shape)) {
|
|
4990
|
+
if (key in existing_shape) {
|
|
4991
|
+
const existing_base = base_type_name(existing_shape[key]);
|
|
4992
|
+
const incoming_base = base_type_name(incoming_shape[key]);
|
|
4993
|
+
if (existing_base !== incoming_base) {
|
|
4994
|
+
throw new Error(
|
|
4995
|
+
`Schema conflict in "${state_name}": key "${key}" has type "${existing_base}" but incoming partial declares "${incoming_base}"`
|
|
4996
|
+
);
|
|
4965
4997
|
}
|
|
4966
4998
|
}
|
|
4967
|
-
return existing.extend(incoming_shape);
|
|
4968
4999
|
}
|
|
4969
|
-
return
|
|
5000
|
+
return existing_object.extend(incoming_shape);
|
|
5001
|
+
}
|
|
5002
|
+
function as_object(schema, side, state_name) {
|
|
5003
|
+
if (schema instanceof ZodObject) return schema;
|
|
5004
|
+
throw new Error(
|
|
5005
|
+
`Cannot merge state schemas for "${state_name}": the ${side} partial's schema is a ${schema.constructor.name}, not a z.object. Partials of the same state are merged by extending their shapes, so declare every partial's state as a plain z.object({ ... }).`
|
|
5006
|
+
);
|
|
4970
5007
|
}
|
|
4971
5008
|
function merge_inits(existing, incoming) {
|
|
4972
5009
|
return () => ({ ...existing(), ...incoming() });
|