@mark1russell7/harness 0.11.4 → 0.11.5

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/build/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { J as Subject, _ as ImageSource, i as ClientImage, r as Client } from "./cell-Di_YHiuB.js";
1
+ import { J as Subject, _ as ImageSource, i as ClientImage, r as Client } from "./cell-lSCgFB54.js";
2
2
  import { z } from "zod";
3
3
  //#region src/schema.d.ts
4
4
  /**
@@ -16,7 +16,8 @@
16
16
  // - ready: the reply to the first query: the connection is idle in the pool (idle, inflight), or
17
17
  // the stream starts (stream).
18
18
  // - sent, ack, fail: each query by its sequence number, with its error.
19
- // - data, error: the end of the query in flight, as the TCP client of the harness tells it.
19
+ // - data, error: the end of the query in flight, as the TCP client of the harness tells it. In idle
20
+ // mode, the close of the socket of the first connection is an error line too: the pool closed it.
20
21
  // - done, deadline: the end of the client.
21
22
  //
22
23
  // The modes are those of the pg client. idle sends one query, closes its connection (the
@@ -60,6 +61,7 @@ public final class ClientHikari {
60
61
  private static volatile boolean stopped = false;
61
62
  private static volatile HikariDataSource pool;
62
63
  private static volatile String connected;
64
+ private static volatile Socket observed;
63
65
  private static String host;
64
66
  private static String port;
65
67
  private static String query;
@@ -216,8 +218,8 @@ public final class ClientHikari {
216
218
 
217
219
  // ---- each connection that the client borrows: its socket, read from pgjdbc
218
220
 
219
- /** This function gives the local address of the socket of a connection, or null. */
220
- private static String localOf(Connection connection) {
221
+ /** This function gives the socket of a connection, from the PGStream of pgjdbc, or null. */
222
+ private static Socket socketOf(Connection connection) {
221
223
  try {
222
224
  PgConnection pg = connection.unwrap(PgConnection.class);
223
225
  Object executor = pg.getQueryExecutor();
@@ -231,23 +233,50 @@ public final class ClientHikari {
231
233
  }
232
234
  if (field == null) return null;
233
235
  field.setAccessible(true);
234
- Socket socket = ((PGStream) field.get(executor)).getSocket();
235
- return socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort();
236
+ return ((PGStream) field.get(executor)).getSocket();
236
237
  } catch (Exception error) {
237
238
  return null;
238
239
  }
239
240
  }
240
241
 
241
242
  private static void seen(Connection connection) {
242
- String local = localOf(connection);
243
- if (local == null || !SEEN.add(local)) return;
243
+ Socket socket = socketOf(connection);
244
+ if (socket == null) return;
245
+ String local = socket.getLocalAddress().getHostAddress() + ":" + socket.getLocalPort();
246
+ if (!SEEN.add(local)) return;
244
247
  emit("socket", "\"role\":\"pool\",\"local\":" + q(local));
245
248
  if (connected == null) {
246
249
  connected = local;
250
+ observed = socket;
247
251
  emit("connected", "\"local\":" + q(local));
248
252
  }
249
253
  }
250
254
 
255
+ /**
256
+ * This function watches the socket of the first connection in idle mode, each 2 ms. The pool
257
+ * closes it when a check finds it dead: pgjdbc closes the socket after a read timeout or an I/O
258
+ * error. That close is the detection of an idle cell, thus it writes an error line.
259
+ */
260
+ private static void watchIdle() {
261
+ Socket socket = observed;
262
+ if (socket == null) return;
263
+ Thread watcher = new Thread(() -> {
264
+ while (!stopped) {
265
+ if (socket.isClosed()) {
266
+ emit("error", "\"errno\":\"CLOSED\",\"local\":" + q(connected));
267
+ return;
268
+ }
269
+ try {
270
+ Thread.sleep(2);
271
+ } catch (InterruptedException stop) {
272
+ return;
273
+ }
274
+ }
275
+ }, "idle-watcher");
276
+ watcher.setDaemon(true);
277
+ watcher.start();
278
+ }
279
+
251
280
  // ---- the counts of the pool, each 5 ms: a line for each change
252
281
 
253
282
  private static void watchPool() {
@@ -413,6 +442,7 @@ public final class ClientHikari {
413
442
  }
414
443
  // the connection went back to the pool at the end of the query: it is idle there
415
444
  emit("ready", "\"reply\":\"ack\"");
445
+ if (mode.equals("idle")) watchIdle();
416
446
  if (mode.equals("inflight")) {
417
447
  while (!Files.exists(go)) Thread.sleep(2);
418
448
  Throwable error = operate(2);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/harness",
4
- "version": "0.11.4",
4
+ "version": "0.11.5",
5
5
  "description": "A fault-injection harness for connection timers: a cell runs a client against a stock target in Docker, through a topology of routers and proxies, a replicated group under Sentinels or a replica set, injects a fault, measures the kernel's own records and judges a prediction. HTTP clients of Go, Node and undici race the keep-alive of a Node server, and the MongoDB driver meets the faults of a replica set. The WebSocket client of @procedures/client drops a silent connection on its own heartbeat, and the harness times that detection and the reconnect from the program's lines and the kernel's stamps.",
6
6
  "keywords": [
7
7
  "fault-injection",