make verify-n8n / deploy/verify-n8n-scheduled-run.sh checks the workflow is active, reads the newest scheduled (mode=trigger) execution from the n8n database, and prints the notify rows. Exit 1 until a scheduled run exists and is green, so it distinguishes 'not yet' from 'failed'. Never runs the workflow and never sends. Document the first-run time and the re-armed monitor.
100 lines
3.3 KiB
Bash
Executable File
100 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Phase 7a (AUD-115): prove the 06:00 n8n schedule fired and the briefs were sent.
|
|
#
|
|
# Read-only. It never runs the workflow and never sends anything, so it is safe to
|
|
# call from a monitor or by hand at any time.
|
|
#
|
|
# Checks:
|
|
# 1. the workflow is active in n8n,
|
|
# 2. the newest scheduled run (mode "trigger") of schoolMorningBrf finished
|
|
# "success" — a hand run (mode "cli") does not count,
|
|
# 3. prints the notify rows so the morning's 8 deliveries can be read.
|
|
#
|
|
# Exit 0 only when 1 and 2 hold. Exit 1 with a clear "no scheduled run yet" when the
|
|
# 06:00 trigger has not fired, so the caller can tell "not yet" from "failed".
|
|
#
|
|
# Usage:
|
|
# deploy/verify-n8n-scheduled-run.sh
|
|
#
|
|
# Environment overrides:
|
|
# CONTAINER n8n container name (default n8n)
|
|
# APP_CONTAINER app container name (default compass-teams-nhs)
|
|
# N8N_DATA_DIR n8n data dir on the host (default /home/sam/Docker/Containers/n8n_data)
|
|
# WF_ID workflow id (default schoolMorningBrf)
|
|
set -euo pipefail
|
|
|
|
CONTAINER="${CONTAINER:-n8n}"
|
|
APP_CONTAINER="${APP_CONTAINER:-compass-teams-nhs}"
|
|
N8N_DATA_DIR="${N8N_DATA_DIR:-/home/sam/Docker/Containers/n8n_data}"
|
|
WF_ID="${WF_ID:-schoolMorningBrf}"
|
|
DB="$N8N_DATA_DIR/database.sqlite"
|
|
|
|
fail=0
|
|
|
|
echo "== 1. the workflow is active in n8n =="
|
|
if docker exec "$CONTAINER" n8n list:workflow --active=true 2>/dev/null | grep -q "$WF_ID"; then
|
|
echo "active: $WF_ID"
|
|
else
|
|
echo "NOT active: $WF_ID — the 06:00 schedule will not fire" >&2
|
|
fail=1
|
|
fi
|
|
|
|
echo
|
|
echo "== 2. the newest scheduled (mode=trigger) execution =="
|
|
if [[ ! -f "$DB" ]]; then
|
|
echo "n8n database not found: $DB (set N8N_DATA_DIR)" >&2
|
|
fail=1
|
|
elif python3 - "$DB" "$WF_ID" <<'PY'
|
|
import datetime, sqlite3, sys
|
|
|
|
db, wf = sys.argv[1], sys.argv[2]
|
|
con = sqlite3.connect(f"file:{db}?mode=ro", uri=True, timeout=8)
|
|
con.row_factory = sqlite3.Row
|
|
rows = list(con.execute(
|
|
"select id, mode, status, startedAt, stoppedAt from execution_entity "
|
|
"where workflowId=? and mode='trigger' order by id desc limit 3", (wf,)))
|
|
if not rows:
|
|
print("no scheduled (mode=trigger) execution yet for", wf)
|
|
sys.exit(1)
|
|
|
|
aedt = datetime.timezone(datetime.timedelta(hours=11))
|
|
|
|
def local(ts):
|
|
for fmt in ("%Y-%m-%d %H:%M:%S.%f", "%Y-%m-%d %H:%M:%S"):
|
|
try:
|
|
dt = datetime.datetime.strptime(ts, fmt).replace(tzinfo=datetime.timezone.utc)
|
|
return dt.astimezone(aedt).strftime("%Y-%m-%d %H:%M %Z")
|
|
except ValueError:
|
|
continue
|
|
return ts
|
|
|
|
for r in rows:
|
|
print(f" id={r['id']} mode={r['mode']} status={r['status']} started={local(r['startedAt'])}")
|
|
|
|
newest = rows[0]
|
|
sys.exit(0 if newest["status"] == "success" else 1)
|
|
PY
|
|
then
|
|
echo "the newest scheduled run finished success"
|
|
else
|
|
echo "the newest scheduled run is not green (or no scheduled run has happened yet)" >&2
|
|
fail=1
|
|
fi
|
|
|
|
echo
|
|
echo "== 3. notify rows (the morning's 8 deliveries) =="
|
|
if docker exec "$APP_CONTAINER" /app/school notify status 2>/dev/null | grep -v '^gateway=' | tail -20; then
|
|
:
|
|
else
|
|
echo "could not read notify status from $APP_CONTAINER" >&2
|
|
fail=1
|
|
fi
|
|
|
|
echo
|
|
if [[ "$fail" -eq 0 ]]; then
|
|
echo "OK: the 06:00 schedule is active, its newest scheduled run is green, rows above"
|
|
else
|
|
echo "NOT YET / FAILED: see the messages above" >&2
|
|
fi
|
|
exit "$fail"
|