9141817867
gates / gates (push) Successful in 24s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
58 lines
3.3 KiB
Python
58 lines
3.3 KiB
Python
"""d1.py <label> [--kill-on-empty] — ONE press of docmost's Update on 9202 (drill catalog), with the
|
|
facts before and after: PG_VERSION (the engine's own file), the seed through docmost's front door,
|
|
the phases with times, the controller's own conversion lines, the undo copies left. Evidence: D/<label>.txt."""
|
|
import json, sys, subprocess, time, threading
|
|
import walk as w, fixtures
|
|
label = sys.argv[1]
|
|
KILL = "--kill-on-empty" in sys.argv
|
|
OUT = open(f"{w.EV}/D/{label}.txt", "w", buffering=1)
|
|
def say(*a):
|
|
w.say(*a); OUT.write(" ".join(map(str, a)) + "\n")
|
|
TOK = json.load(open(w.SC + "/seed-tokens.json"))
|
|
def pgver():
|
|
return w.guest('docker exec docmost-postgres sh -c \'cat "$PGDATA/PG_VERSION"\' 2>&1; docker inspect docmost-postgres --format "{{.Config.Image}}" 2>&1').split()
|
|
def seed():
|
|
return fixtures.FIXTURES["docmost"].verify(w, "c-docs", TOK["docmost"], lambda m: None)
|
|
w.login()
|
|
w.sync_rescan("docmost", "postgres:18-alpine")
|
|
st = w.stack("docmost")
|
|
say(f"# {label} — {time.strftime('%Y-%m-%dT%H:%M:%S%z')}; controller {w.guest('cat /etc/felhom-controller-image').strip()}")
|
|
say(f"before: PG_VERSION/image={pgver()} pinned={(st.get('app_config') or {}).get('pinned_images')} catalog={st.get('catalog_images')}")
|
|
say(f"before: seed reads back through the front door = {seed()}")
|
|
since = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip()
|
|
killer = None
|
|
if KILL:
|
|
def kill():
|
|
# wait INSIDE the guest for the controller's own "emptied" line, then SIGKILL its main process
|
|
out = w.guest(f"""timeout 600 sh -c 'docker logs -f --since {since} felhom-controller 2>&1 | grep -m1 "emptied"'
|
|
pid=$(docker inspect felhom-controller --format '{{{{.State.Pid}}}}'); kill -9 $pid; echo "KILLED controller pid $pid at $(date -u +%T.%N)" """, timeout=700)
|
|
say(" [kill] " + out.strip().replace("\n", " | "))
|
|
killer = threading.Thread(target=kill); killer.start(); time.sleep(2)
|
|
r = w.press_update("docmost", poll=0.5, cap_s=1500)
|
|
if killer:
|
|
killer.join()
|
|
say(" [kill] waiting for the controller to come back and the journal to be resumed")
|
|
for i in range(120):
|
|
time.sleep(5)
|
|
try:
|
|
w.login(); s2 = w.stack("docmost")
|
|
except SystemExit:
|
|
continue
|
|
if not s2.get("updating") and s2.get("update_phase") in ("undone", "failed", "done"):
|
|
r["after_restart"] = {"phase": s2.get("update_phase"), "error": s2.get("update_error"), "hold": s2.get("hold_reason")}
|
|
break
|
|
for p in r.get("phases", []):
|
|
OUT.write(f" phase +{p['t']}s {p['phase']} | {p['label']} | err={p['error']}\n")
|
|
say(f"result: {json.dumps({k: v for k, v in r.items() if k != 'phases'}, ensure_ascii=False)[:900]}")
|
|
for i in range(40):
|
|
if w.app_curl("c-docs", "/")[1] == "200":
|
|
break
|
|
time.sleep(5)
|
|
st = w.stack("docmost")
|
|
say(f"after: PG_VERSION/image={pgver()} pinned={(st.get('app_config') or {}).get('pinned_images')} conversion_copy={(st.get('app_config') or {}).get('conversion_copy')}")
|
|
say(f"after: seed reads back through the front door = {seed()}")
|
|
say("controller lines (docmost / conversion):")
|
|
OUT.write(w.guest(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'update docmost|CONVERT|pg_dumpall|emptied|loaded into|resum|UNDO' | cut -c1-400") + "\n")
|
|
OUT.write("undo copies now: " + w.guest("docker volume ls -q --filter label=felhom.undo-copy-of=docmost | tr '\\n' ' '") + "\n")
|
|
say("done")
|