@openlfcp/client 0.2.0-beta.8 → 0.2.0-beta.9

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.
Files changed (2) hide show
  1. package/dist/outbound.js +21 -2
  2. package/package.json +5 -5
package/dist/outbound.js CHANGED
@@ -36,6 +36,8 @@ const PER_OBJECT = new Set([
36
36
  const CODE_NAMES = new Map(Object.entries(ERROR_CODE).map(([name, code]) => [code, name]));
37
37
  /** Room left in a message for the envelope and body around the objects. */
38
38
  const OVERHEAD = 1024;
39
+ /** How many expired flights are remembered for a late answer. */
40
+ const EXPIRED_KEPT = 1024;
39
41
  const AT_ONCE = { nextAttempt: () => null };
40
42
  /** Data Units by actor, then actor sequence; unparsable bytes last (they are blocked when sent). */
41
43
  function unitOrder(a, b) {
@@ -65,6 +67,16 @@ export class OutboundQueue {
65
67
  #maxMessageBytes = DEFAULT_MAX_MESSAGE_BYTES;
66
68
  /** message ID hex → what it carried */
67
69
  #flights = new Map();
70
+ /**
71
+ * Flights that expired unanswered (#expire), by message ID, the most
72
+ * recent {@link EXPIRED_KEPT}: a late answer to one is still an answer to
73
+ * our message, correlated for §4.1's acceptance evidence. Without them, an
74
+ * ACK handled after the timeout sweep (a busy event loop: the sweep's
75
+ * timer runs before the waiting message) dequeued the items as
76
+ * uncorrelated, their batch was "evidence-unavailable" for good, and no
77
+ * later ACK could change it (the Shared Tasks soak of 0.4.0-beta.17).
78
+ */
79
+ #expired = new Map();
68
80
  /** item ID hex → message ID hex */
69
81
  #inFlight = new Map();
70
82
  /**
@@ -99,6 +111,9 @@ export class OutboundQueue {
99
111
  if (flight.deadline > at)
100
112
  continue;
101
113
  this.#flights.delete(key);
114
+ this.#expired.set(key, flight);
115
+ if (this.#expired.size > EXPIRED_KEPT)
116
+ this.#expired.delete(this.#expired.keys().next().value);
102
117
  for (const id of flight.itemIds)
103
118
  if (this.#inFlight.get(toHex(id)) === key) {
104
119
  this.#inFlight.delete(toHex(id));
@@ -261,8 +276,12 @@ export class OutboundQueue {
261
276
  return undefined;
262
277
  const key = toHex(messageId);
263
278
  const flight = this.#flights.get(key);
264
- if (flight === undefined)
265
- return undefined;
279
+ if (flight === undefined) {
280
+ // A late answer to a message whose flight expired: ours, correlated.
281
+ const late = this.#expired.get(key);
282
+ this.#expired.delete(key);
283
+ return late;
284
+ }
266
285
  this.#flights.delete(key);
267
286
  for (const id of flight.itemIds) {
268
287
  if (this.#inFlight.get(toHex(id)) === key)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlfcp/client",
3
- "version": "0.2.0-beta.8",
3
+ "version": "0.2.0-beta.9",
4
4
  "description": "LFCP client: session, Control Plane and Data Plane synchronization.",
5
5
  "keywords": [
6
6
  "openlfcp",
@@ -42,9 +42,9 @@
42
42
  "tag": "beta"
43
43
  },
44
44
  "dependencies": {
45
- "@openlfcp/core": "^0.2.0-beta.8",
46
- "@openlfcp/storage": "^0.2.0-beta.8",
47
- "@openlfcp/crypto": "^0.2.0-beta.8",
48
- "@openlfcp/wire": "^0.2.0-beta.8"
45
+ "@openlfcp/core": "^0.2.0-beta.9",
46
+ "@openlfcp/storage": "^0.2.0-beta.9",
47
+ "@openlfcp/wire": "^0.2.0-beta.9",
48
+ "@openlfcp/crypto": "^0.2.0-beta.9"
49
49
  }
50
50
  }