@biffo/cli 0.296.14 → 0.296.15
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/package.json +1 -1
- package/scripts/pg-test-db.sh +84 -4
package/package.json
CHANGED
package/scripts/pg-test-db.sh
CHANGED
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
# eval "$(sh scripts/pg-test-db.sh --export)" # export BIFFO_TEST_PG_DSN and TABSII_TEST_PG_DSN
|
|
44
44
|
# sh scripts/pg-test-db.sh # print the DSN on stdout
|
|
45
45
|
# sh scripts/pg-test-db.sh --recreate # force a rebuild
|
|
46
|
+
# sh scripts/pg-test-db.sh --reap # housekeeping only: reap and exit
|
|
46
47
|
#
|
|
47
48
|
# Only the DSN reaches stdout, so it is safe to capture; progress goes to stderr.
|
|
48
49
|
#
|
|
@@ -164,10 +165,12 @@ CONTAINER="${BIFFO_PG_CONTAINER:-biffo-pg-test-$_checkout_suffix}"
|
|
|
164
165
|
|
|
165
166
|
RECREATE=0
|
|
166
167
|
EXPORT=0
|
|
168
|
+
REAP_ONLY=0
|
|
167
169
|
for arg in "$@"; do
|
|
168
170
|
case "$arg" in
|
|
169
171
|
--recreate) RECREATE=1 ;;
|
|
170
172
|
--export) EXPORT=1 ;;
|
|
173
|
+
--reap) REAP_ONLY=1 ;;
|
|
171
174
|
-h | --help)
|
|
172
175
|
sed -n '2,72p' "$0" | sed 's/^#\{1,2\} \{0,1\}//'
|
|
173
176
|
exit 0
|
|
@@ -250,6 +253,7 @@ if [ "$BIFFO_PG_REAP_HOURS" -gt 0 ] 2>/dev/null && command -v docker >/dev/null
|
|
|
250
253
|
say "cannot compute a reap cutoff on this date(1); skipping container reaping"
|
|
251
254
|
else
|
|
252
255
|
_reaped=0
|
|
256
|
+
_reaped_gone=0
|
|
253
257
|
_considered=0
|
|
254
258
|
# TWO filters, not one literal name (#1383). The label is what containers
|
|
255
259
|
# created from here now carry; the name prefix keeps covering every one
|
|
@@ -272,14 +276,65 @@ if [ "$BIFFO_PG_REAP_HOURS" -gt 0 ] 2>/dev/null && command -v docker >/dev/null
|
|
|
272
276
|
_made=$(docker inspect -f '{{.Created}}' "$_c" 2>/dev/null | cut -c1-19)
|
|
273
277
|
[ -z "$_made" ] && continue
|
|
274
278
|
_considered=$((_considered + 1))
|
|
279
|
+
# ── Ownership beats age, where ownership is knowable ─────────────────
|
|
280
|
+
#
|
|
281
|
+
# Age was only ever a PROXY. The container is keyed to a checkout
|
|
282
|
+
# (see `CONTAINER` above), so the honest question is not "is this old?"
|
|
283
|
+
# but "does the checkout that owns it still exist?" -- and once the
|
|
284
|
+
# worktree is deleted the answer is a fact, not an estimate. A container
|
|
285
|
+
# whose checkout is gone can never be reused by anything, so there is no
|
|
286
|
+
# 4-second-rebuild trade to weigh: it is pure garbage the moment the
|
|
287
|
+
# directory disappears.
|
|
288
|
+
#
|
|
289
|
+
# Measured 2026-08-22 on one workstation: 42 live containers, of which 19
|
|
290
|
+
# belonged to checkouts that no longer existed. Under the age rule alone
|
|
291
|
+
# those 19 each held a running Postgres and ~500MB for up to 24 more
|
|
292
|
+
# hours -- and #703's real complaint was never disk, it was that these
|
|
293
|
+
# compete for the same page cache and I/O as the lane being timed.
|
|
294
|
+
#
|
|
295
|
+
# The path is read from a LABEL SET AT CREATION, never derived from the
|
|
296
|
+
# container's name. Deriving it would mean hashing candidate paths to see
|
|
297
|
+
# which produces this suffix, and the `biffo-pg-test-` prefix is shared by
|
|
298
|
+
# every repo in the estate -- so a run in one repo, finding no matching
|
|
299
|
+
# worktree of its OWN, would confidently reap a container another repo's
|
|
300
|
+
# test lane was mid-run against. The label makes the claim self-describing
|
|
301
|
+
# and repo-independent.
|
|
302
|
+
#
|
|
303
|
+
# Containers created before this label existed report an empty value and
|
|
304
|
+
# fall through to the age rule below, exactly as `biffo.ephemeral=1`
|
|
305
|
+
# migrated in (#1383). Nothing is stranded; they simply age out once.
|
|
306
|
+
_owner=$(docker inspect -f '{{index .Config.Labels "biffo.checkout"}}' "$_c" 2>/dev/null)
|
|
307
|
+
if [ -n "$_owner" ] && [ "$_owner" != "<no value>" ] && [ ! -d "$_owner" ]; then
|
|
308
|
+
if docker rm -f -v "$_c" >/dev/null 2>&1; then
|
|
309
|
+
_reaped=$((_reaped + 1))
|
|
310
|
+
_reaped_gone=$((_reaped_gone + 1))
|
|
311
|
+
fi
|
|
312
|
+
continue
|
|
313
|
+
fi
|
|
275
314
|
# Both are UTC ISO-8601 to the second, so a string compare IS a time
|
|
276
315
|
# compare -- no epoch conversion, and portable across date(1) flavours.
|
|
277
316
|
if awk -v a="$_made" -v b="$_reap_cutoff" 'BEGIN { exit !(a < b) }'; then
|
|
278
|
-
|
|
317
|
+
# `-v` REMOVES THE CONTAINER'S ANONYMOUS VOLUME WITH IT.
|
|
318
|
+
#
|
|
319
|
+
# Without it every reap orphans a full Postgres data directory. Measured on one
|
|
320
|
+
# workstation 2026-08-20: 413 dangling volumes holding 104.8GB -- 95% of all local
|
|
321
|
+
# volume space -- against 11 live containers totalling 2.5MB. The containers were
|
|
322
|
+
# tidied and their data was not, so the leak grew by roughly a database per reap
|
|
323
|
+
# and nothing pointed at it.
|
|
324
|
+
#
|
|
325
|
+
# It is invisible by construction: `docker ps` looks clean, the reaper reports how
|
|
326
|
+
# many it removed, and the space is only findable with `docker volume ls -qf
|
|
327
|
+
# dangling=true`. The first symptom is a full disk somewhere unrelated.
|
|
328
|
+
docker rm -f -v "$_c" >/dev/null 2>&1 && _reaped=$((_reaped + 1))
|
|
279
329
|
fi
|
|
280
330
|
done
|
|
281
|
-
|
|
282
|
-
|
|
331
|
+
# Two reasons, counted apart. A single total would let the cheap, certain
|
|
332
|
+
# rule and the age guess read as one number, and the whole point of the
|
|
333
|
+
# ownership rule is that it is NOT a guess -- if it ever reaps something
|
|
334
|
+
# still wanted, that total must say so on its own.
|
|
335
|
+
if [ "$_reaped" -gt 0 ]; then
|
|
336
|
+
say "reaped $_reaped of $_considered container(s): $_reaped_gone whose checkout no longer exists, $((_reaped - _reaped_gone)) unused for over ${BIFFO_PG_REAP_HOURS}h (set BIFFO_PG_REAP_HOURS=0 to disable)"
|
|
337
|
+
fi
|
|
283
338
|
|
|
284
339
|
# ── What the reaper can SEE but must not touch ──────────────────────────
|
|
285
340
|
#
|
|
@@ -330,10 +385,31 @@ if [ "$BIFFO_PG_REAP_HOURS" -gt 0 ] 2>/dev/null && command -v docker >/dev/null
|
|
|
330
385
|
say "NOT reaped -- Postgres containers over ${BIFFO_PG_REAP_HOURS}h old that this script did not create:"
|
|
331
386
|
for _u in $_unclaimed; do say " $_u"; done
|
|
332
387
|
say " A stale one costs test failures that belong to nobody (#1383). Remove by hand"
|
|
333
|
-
say " (docker rm -f <name>
|
|
388
|
+
say " (docker rm -f -v <name> -- the -v matters, or its data volume is orphaned),"
|
|
389
|
+
say " or start it with --label biffo.ephemeral=1 to have it reaped."
|
|
334
390
|
fi
|
|
335
391
|
}
|
|
336
392
|
fi
|
|
393
|
+
|
|
394
|
+
# `--reap` is housekeeping ONLY: reap, report, and stop before starting or
|
|
395
|
+
# touching a server.
|
|
396
|
+
#
|
|
397
|
+
# The reaper is otherwise LAZY -- it runs only when something else runs the
|
|
398
|
+
# lane, so the moment the fleet goes quiet nothing reclaims anything and the
|
|
399
|
+
# mess sits until the next test. That is the opposite of what is wanted: idle
|
|
400
|
+
# is exactly when reclaiming is free. This flag is the callable form, so a
|
|
401
|
+
# worktree teardown or a periodic sweep can collect without standing up a
|
|
402
|
+
# Postgres nobody asked for.
|
|
403
|
+
if [ "$REAP_ONLY" -eq 1 ]; then
|
|
404
|
+
exit 0
|
|
405
|
+
fi
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
# Guard the case above: with reaping disabled there is nothing for `--reap` to
|
|
409
|
+
# do, and it must still not fall through into starting a server.
|
|
410
|
+
if [ "$REAP_ONLY" -eq 1 ]; then
|
|
411
|
+
say "reaping is disabled (BIFFO_PG_REAP_HOURS=0); nothing to do"
|
|
412
|
+
exit 0
|
|
337
413
|
fi
|
|
338
414
|
|
|
339
415
|
if ! psql_admin -c 'SELECT 1' >/dev/null 2>&1; then
|
|
@@ -352,7 +428,11 @@ if ! psql_admin -c 'SELECT 1' >/dev/null 2>&1; then
|
|
|
352
428
|
# is still scanned, but it only ever described containers this script named;
|
|
353
429
|
# anything started under another name was outside the reaper's denominator
|
|
354
430
|
# entirely. A label travels with the container whatever it is called.
|
|
431
|
+
# `biffo.checkout` is what makes the container's owner knowable after the
|
|
432
|
+
# fact. The reaper above uses it to remove a container the moment its
|
|
433
|
+
# checkout is deleted, rather than waiting out a 24-hour proxy.
|
|
355
434
|
docker run -d --name "$CONTAINER" --label biffo.ephemeral=1 \
|
|
435
|
+
--label "biffo.checkout=$REPO_ROOT" \
|
|
356
436
|
-e POSTGRES_PASSWORD="$PASS" -p "$PORT:5432" "$IMAGE" >/dev/null
|
|
357
437
|
fi
|
|
358
438
|
# Polled, not slept: a cold image pull and a warm restart differ by an order of
|