@mark1russell7/kind 0.12.2 → 0.12.4
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 +2 -0
- package/build/index.d.ts +2 -2
- package/build/index.js +23 -7
- package/build/index.js.map +1 -1
- package/build/{judge-BRxKwiSp.js → judge-45z0yZ-r.js} +103 -8
- package/build/judge-45z0yZ-r.js.map +1 -0
- package/build/{judge-3auejM2S.d.ts → judge-BbzdXnBz.d.ts} +66 -2
- package/build/judge.d.ts +2 -2
- package/build/judge.js +1 -1
- package/package.json +1 -1
- package/build/judge-BRxKwiSp.js.map +0 -1
|
@@ -23,6 +23,61 @@ const showBand = (band) => {
|
|
|
23
23
|
const { lo, hi } = secondsOf(band);
|
|
24
24
|
return `[${lo}, ${hi}] s`;
|
|
25
25
|
};
|
|
26
|
+
/** This function rounds a time to the microsecond, thus a band has no float residue. */
|
|
27
|
+
const us = (value) => Math.round(value * 1e6) / 1e6;
|
|
28
|
+
/**
|
|
29
|
+
* This function gives the end band of a window with the backlog term (`BacklogTerm`). It adds n × d
|
|
30
|
+
* to each end of `end`, the end band without the term. The value n is the sessions on the target.
|
|
31
|
+
*/
|
|
32
|
+
const backlogEnd = (end, term, sessions) => {
|
|
33
|
+
const ends = secondsOf(end);
|
|
34
|
+
const drain = secondsOf(term.drain);
|
|
35
|
+
return bandOf(us(ends.lo + sessions * drain.lo), us(ends.hi + sessions * drain.hi));
|
|
36
|
+
};
|
|
37
|
+
/** This function gives a count rounded to six places, thus 10 s / 20 ms gives 500 and not 499.99999. */
|
|
38
|
+
const counted = (value) => Math.round(value * 1e6) / 1e6;
|
|
39
|
+
/** This function gives the turn of a session in seconds: the mean period of a client times its sessions. */
|
|
40
|
+
const turnOf = (mean, connections) => {
|
|
41
|
+
const turn = valueIn(mean, "s") * connections;
|
|
42
|
+
if (!(turn > 0)) throw new RangeError(`a turn of ${turn} s cannot count requests`);
|
|
43
|
+
return turn;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* This function gives the drain failures of one session on the target (SYS-43). A session fails a
|
|
47
|
+
* request each turn until the window closes. With n sessions on the target, the window closes up to
|
|
48
|
+
* n × d.hi after the band end (`backlogEnd`). Thus one session fails 0 to ceil(n × d.hi / turn)
|
|
49
|
+
* requests in the drain. The turn is the mean period of a client (`mean`) times its sessions
|
|
50
|
+
* (`connections`). The term r is not in this band.
|
|
51
|
+
*/
|
|
52
|
+
const drainBand = (term, mean, connections, sessions) => {
|
|
53
|
+
const turn = turnOf(mean, connections);
|
|
54
|
+
return {
|
|
55
|
+
lo: 0,
|
|
56
|
+
hi: Math.ceil(counted(sessions * valueIn(term.drain.hi, "s") / turn))
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* This function gives the failed requests that the backlog term predicts (`BacklogTerm`). Each of
|
|
61
|
+
* the n sessions on the target gets a request each turn. The turn is the measured mean period of a
|
|
62
|
+
* client (`mean`) times the sessions of the client (`connections`). The requests of a session fail
|
|
63
|
+
* from the start of the window to the band end (`span`). That span holds `span / turn` requests, one
|
|
64
|
+
* less at its low edge and one more at its high edge. Each session fails r more requests in its drain time.
|
|
65
|
+
*
|
|
66
|
+
* A term with `drains` (SYS-43) also adds the drain failures of each session (`drainBand`).
|
|
67
|
+
*/
|
|
68
|
+
const requestBand = (term, span, mean, connections, sessions) => {
|
|
69
|
+
const turn = turnOf(mean, connections);
|
|
70
|
+
const each = counted(valueIn(span, "s") / turn);
|
|
71
|
+
if (term.drains === true && term.drain === void 0) throw new RangeError("a term with drains has no drain time d");
|
|
72
|
+
const drained = term.drains === true ? drainBand({ drain: term.drain }, mean, connections, sessions) : {
|
|
73
|
+
lo: 0,
|
|
74
|
+
hi: 0
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
lo: sessions * (Math.floor(each) - 1 + term.requests.lo + drained.lo),
|
|
78
|
+
hi: sessions * (Math.ceil(each) + 1 + term.requests.hi + drained.hi)
|
|
79
|
+
};
|
|
80
|
+
};
|
|
26
81
|
//#endregion
|
|
27
82
|
//#region src/names.ts
|
|
28
83
|
/** These are the ports of the app: its server, and its health server for the probes. */
|
|
@@ -427,7 +482,8 @@ const windowOf = (prediction) => prediction.kind === "window" ? prediction : pre
|
|
|
427
482
|
const observationAfter = (cell) => {
|
|
428
483
|
const window = windowOf(cell.prediction);
|
|
429
484
|
if (window === null || window.end === null) return null;
|
|
430
|
-
|
|
485
|
+
const drained = window.backlog === void 0 ? 0 : window.backlog.most * valueIn(window.backlog.drain.hi, "ms");
|
|
486
|
+
return seconds(sec(valueIn(window.end.band.hi, "ms") + drained + valueIn(cell.workload.timeout, "ms") + NOISE));
|
|
431
487
|
};
|
|
432
488
|
/**
|
|
433
489
|
* This function gives the earliest end of the observation of a run, as a stamp, or null when its
|
|
@@ -585,6 +641,27 @@ const removalOfCycles = (cell, run, prediction, done) => {
|
|
|
585
641
|
tail: inner.tail
|
|
586
642
|
};
|
|
587
643
|
};
|
|
644
|
+
/**
|
|
645
|
+
* This function counts the failed requests of a run with the backlog term (`requestBand`). The span
|
|
646
|
+
* is from the start of the window to the end band without the term. The turn of a session comes
|
|
647
|
+
* from the measured mean period of the clients. A run with no measured period cannot be counted.
|
|
648
|
+
*/
|
|
649
|
+
const countOf = (cell, window, term, onTarget, period, failed) => {
|
|
650
|
+
if (period === void 0) return {
|
|
651
|
+
ok: false,
|
|
652
|
+
why: "the run has no measured period, thus the backlog term cannot count its failed requests"
|
|
653
|
+
};
|
|
654
|
+
const span = seconds(Math.round((valueIn(window.end.band.hi, "s") - valueIn(window.start.band.lo, "s")) * 1e6) / 1e6);
|
|
655
|
+
const band = requestBand(term, span, period.mean, cell.workload.connections ?? 1, onTarget);
|
|
656
|
+
const at = `the count [${band.lo}, ${band.hi}] of ${onTarget} session${onTarget === 1 ? "" : "s"} on the target at a mean period of ${Math.round(valueIn(period.mean, "ms") * 1e3) / 1e3} ms`;
|
|
657
|
+
return failed >= band.lo && failed <= band.hi ? {
|
|
658
|
+
ok: true,
|
|
659
|
+
why: `in ${at}`
|
|
660
|
+
} : {
|
|
661
|
+
ok: false,
|
|
662
|
+
why: `${failed} failed requests, outside ${at}`
|
|
663
|
+
};
|
|
664
|
+
};
|
|
588
665
|
/** This function judges one run against the prediction of its cell. */
|
|
589
666
|
const checkRun = (cell, run) => {
|
|
590
667
|
const lines = run.lines;
|
|
@@ -614,7 +691,10 @@ const checkRun = (cell, run) => {
|
|
|
614
691
|
case "window": {
|
|
615
692
|
const each = prediction.each === true;
|
|
616
693
|
const opens = secondsOf(prediction.start.band);
|
|
617
|
-
const
|
|
694
|
+
const backlog = prediction.backlog;
|
|
695
|
+
const onTarget = facts.sessions?.onTarget;
|
|
696
|
+
if (backlog !== void 0 && (prediction.end === null || prediction.end.from !== prediction.start.from || onTarget === void 0)) return done(false, onTarget === void 0 ? "the run has no sessions on the target at the fault, thus the backlog term has no n" : "a window with the backlog term has an end with the reference of its start", null);
|
|
697
|
+
const closes = prediction.end === null ? null : secondsOf(backlog === void 0 ? prediction.end.band : backlogEnd(prediction.end.band, backlog, onTarget));
|
|
618
698
|
const droppedAfter = (origin, propagation) => (node) => {
|
|
619
699
|
const propagated = propagation[node];
|
|
620
700
|
return origin === null || propagated === void 0 || propagated === null ? null : origin + valueIn(propagated.by, "ms");
|
|
@@ -708,6 +788,8 @@ const checkRun = (cell, run) => {
|
|
|
708
788
|
if (others.length > 0) problems.push(`${others.length} failed requests on nodes whose kube-proxy did not pause`);
|
|
709
789
|
if (wrong.length > 0) problems.push(`${wrong.length} failed requests in the window ended ${JSON.stringify(outcomesOf(wrong))}, not ${allowed.join(", ")}`);
|
|
710
790
|
if (prediction.certain && relevant.length === 0) problems.push("no request failed in a window that the law opens");
|
|
791
|
+
const counted = backlog === void 0 ? null : countOf(cell, prediction, backlog, onTarget, facts.period, relevant.length);
|
|
792
|
+
if (counted !== null && !counted.ok) problems.push(counted.why);
|
|
711
793
|
const final = windows.reduce((a, b) => (b.end ?? Number.NEGATIVE_INFINITY) > (a.end ?? Number.NEGATIVE_INFINITY) ? b : a);
|
|
712
794
|
if (flaps && prediction.certain && relevant.length > 0) windows.forEach((window, k) => {
|
|
713
795
|
const own = relevant.filter((request) => request.t >= window.lo && request.t <= window.hi);
|
|
@@ -725,7 +807,7 @@ const checkRun = (cell, run) => {
|
|
|
725
807
|
const inside = relevant.filter((request) => !late.includes(request));
|
|
726
808
|
const span = inside.length === 0 ? 0 : sec(inside.at(-1).t - inside[0].t);
|
|
727
809
|
const where = each ? `the windows of ${windows.length} deleted replicas` : flaps ? `the windows of ${windows.length} cycles` : "the window";
|
|
728
|
-
const agrees = reused.length === 0 ? `${relevant.length} failed requests, all in ${where} (span ${span} s)` : `${inside.length} failed requests in ${where} (span ${span} s), and ${reused.length} on a port that a reset closed
|
|
810
|
+
const agrees = (reused.length === 0 ? `${relevant.length} failed requests, all in ${where} (span ${span} s)` : `${inside.length} failed requests in ${where} (span ${span} s), and ${reused.length} on a port that a reset closed`) + (counted === null ? "" : `, ${counted.why}`);
|
|
729
811
|
const checked = done(problems.length === 0, problems.length === 0 ? agrees : problems.join("; "), relevant.length);
|
|
730
812
|
if (problems.length > 0) return checked;
|
|
731
813
|
const notes = [];
|
|
@@ -1155,7 +1237,7 @@ const upgradeTrigger = (trigger) => {
|
|
|
1155
1237
|
};
|
|
1156
1238
|
};
|
|
1157
1239
|
const upgradeWindow = (window) => {
|
|
1158
|
-
const { afterReset, propagation, ...rest } = window;
|
|
1240
|
+
const { afterReset, propagation, backlog, ...rest } = window;
|
|
1159
1241
|
return {
|
|
1160
1242
|
...rest,
|
|
1161
1243
|
start: {
|
|
@@ -1170,7 +1252,11 @@ const upgradeWindow = (window) => {
|
|
|
1170
1252
|
life: seconds(afterReset.life),
|
|
1171
1253
|
outcome: afterReset.outcome
|
|
1172
1254
|
} },
|
|
1173
|
-
...propagation === void 0 ? {} : { propagation: band(propagation) }
|
|
1255
|
+
...propagation === void 0 ? {} : { propagation: band(propagation) },
|
|
1256
|
+
...backlog === void 0 ? {} : { backlog: {
|
|
1257
|
+
...backlog,
|
|
1258
|
+
drain: band(backlog.drain)
|
|
1259
|
+
} }
|
|
1174
1260
|
};
|
|
1175
1261
|
};
|
|
1176
1262
|
const upgradePrediction = (prediction) => {
|
|
@@ -1318,7 +1404,7 @@ const atBand = (from, band) => {
|
|
|
1318
1404
|
const predictionText = (prediction) => {
|
|
1319
1405
|
switch (prediction.kind) {
|
|
1320
1406
|
case "none": return prediction.outcomes === void 0 ? "no failure" : `no ${prediction.outcomes.join(", ")}`;
|
|
1321
|
-
case "window": return `failures only from ${atBand(prediction.start.from, prediction.start.band)}${prediction.end === null ? "" : ` to ${atBand(prediction.end.from, prediction.end.band)}`}${prediction.each === true ? ", of each deleted replica" : ""}${prediction.flaps === true ? ", in each cycle" : ""}${prediction.nodes === "paused" ? ", on the paused node" : ""}${prediction.certain ? ", at least one" : ""}${prediction.outcomes === void 0 ? "" : `, each one ${prediction.outcomes.join(" or ")}`}${prediction.afterReset === void 0 ? "" : `, or a ${prediction.afterReset.outcome} up to ${format(prediction.afterReset.life)} after a reset on its port`}${prediction.propagation === void 0 ? "" : `, the rules drop the replica in ${showBand(prediction.propagation)}`}`;
|
|
1407
|
+
case "window": return `failures only from ${atBand(prediction.start.from, prediction.start.band)}${prediction.end === null ? "" : ` to ${atBand(prediction.end.from, prediction.end.band)}`}${prediction.each === true ? ", of each deleted replica" : ""}${prediction.flaps === true ? ", in each cycle" : ""}${prediction.nodes === "paused" ? ", on the paused node" : ""}${prediction.certain ? ", at least one" : ""}${prediction.outcomes === void 0 ? "" : `, each one ${prediction.outcomes.join(" or ")}`}${prediction.afterReset === void 0 ? "" : `, or a ${prediction.afterReset.outcome} up to ${format(prediction.afterReset.life)} after a reset on its port`}${prediction.propagation === void 0 ? "" : `, the rules drop the replica in ${showBand(prediction.propagation)}`}${prediction.backlog === void 0 ? "" : `, the end n × ${showBand(prediction.backlog.drain)} later and ${prediction.backlog.requests.lo}–${prediction.backlog.requests.hi} more failures for each of the n sessions on the target${prediction.backlog.drains === true ? ", and its failures each turn in the drain of the n sessions" : ""}, counted at the measured period`}`;
|
|
1322
1408
|
case "removal": return `Service empty in ${showBand(prediction.band)}${prediction.flaps === true ? " after each fault, and ready again before the next" : ""}${prediction.window === void 0 ? "" : `; ${predictionText(prediction.window)}`}`;
|
|
1323
1409
|
case "leaves": return `the replica leaves in ${showBand(prediction.band)}${prediction.window === void 0 ? "" : `; ${predictionText(prediction.window)}`}`;
|
|
1324
1410
|
case "restarts": return prediction.band === null ? "no restart" : `each replica SIGTERM in ${showBand(prediction.band)}`;
|
|
@@ -1618,6 +1704,15 @@ const recordOf = (a, main) => {
|
|
|
1618
1704
|
propagation: band.optional(),
|
|
1619
1705
|
flaps: z.boolean().optional(),
|
|
1620
1706
|
outcomes: z.array(z.string()).optional(),
|
|
1707
|
+
backlog: z.object({
|
|
1708
|
+
drain: band,
|
|
1709
|
+
requests: z.object({
|
|
1710
|
+
lo: count,
|
|
1711
|
+
hi: count
|
|
1712
|
+
}),
|
|
1713
|
+
most: count,
|
|
1714
|
+
drains: z.boolean().optional()
|
|
1715
|
+
}).optional(),
|
|
1621
1716
|
why: z.string()
|
|
1622
1717
|
});
|
|
1623
1718
|
const none = z.object({
|
|
@@ -1843,6 +1938,6 @@ const readRecord = (data) => {
|
|
|
1843
1938
|
throw new Error(`a kind cell record has the format ${FORMAT} or ${FORMAT_V1}, not ${String(format)}`);
|
|
1844
1939
|
};
|
|
1845
1940
|
//#endregion
|
|
1846
|
-
export { restartsAt as $, RELATIVE as A, dropOf as B, observationEnd as C,
|
|
1941
|
+
export { restartsAt as $, RELATIVE as A, dropOf as B, observationEnd as C, drainBand as Ct, reusesReset as D, showBand as Dt, referenceOf as E, secondsOf as Et, TCP_STATE as F, kernelCounts as G, failuresOf as H, backendsAt as I, podsAt as J, outcomesOf as K, byClients as L, middle as M, quantileOf as N, unitOf as O, HBONE_PORT as P, restartOf as Q, byNode as R, observationAfter as S, bandOf as St, propagationSource as T, seconds as Tt, intakeOf as U, emptyOf as V, isTunnelState as W, recordsOf as X, podsOf as Y, requestsOf as Z, checkRun as _, LOG_LABEL as _t, calibrationOf as a, sliceEmptyOf as at, factsOf as b, SERVER as bt, predictionText as c, slicesOf as ct, FORMAT_V1 as d, transitionOf as dt, rulesOf as et, judge as f, tunnelsOf as ft, LAST_SLACK as g, HEALTH_PORT as gt, KIND_NOISE as h, CLIENT as ht, readRecord as i, sliceDropOf as it, medianInterval as j, updatesOf as k, timeSpread as l, socketsOf as lt, upgradeCell as m, ztunnelReplaced as mt, kindCellRecordSchema as n, signalOf as nt, cellsTable as o, sliceReadyAt as ot, upgrade as p, ztunnelPodsOf as pt, periodOf as q, kindCellRecordV1Schema as r, signalsOf as rt, medianText as s, sliceReadyOf as st, STAGES as t, sessionsAt as tt, FORMAT as u, stoppingOf as ut, cyclesOf as v, PORT as vt, propagationOf as w, requestBand as wt, judgeKind as x, backlogEnd as xt, deletionsOf as y, REDIS as yt, deletionOf as z };
|
|
1847
1942
|
|
|
1848
|
-
//# sourceMappingURL=judge-
|
|
1943
|
+
//# sourceMappingURL=judge-45z0yZ-r.js.map
|