Run events in the database: Runs page and Agent run card on the Dokploy Portal

Snapshot of D:\Ecw Process 65c92c5 (2026-10-30).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ManikandanandClaude Opus 5.5 committed 2026-10-30 11:28:26 +05:30
1 parent d500f750da
commit 840272032a
9 files changed
+655 -46

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
r"""
Load this PC's older Run events into `dbo.CV_RunEvent` (2026-10-30), once,
so the Portal on Dokploy lists the Runs from before the bot copied its
events to the database itself. A Run already in the table is skipped, so a
second run of this tool adds nothing.
python tools\import_run_events.py # import
python tools\import_run_events.py --dry-run # only say what it would do
Run it from PowerShell on the bot PC (Windows login to the database).
"""
import sys
import json
from datetime import datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from ecw_bot import settings as cfg # noqa: E402
RUN_PREFIX = "events_"
def rows_of(run_id: str, text: str) -> list:
"""(run_id, at, kind, line) per timed JSON line; a bad line skipped."""
out = []
for line in text.splitlines():
try:
e = json.loads(line)
at = datetime.fromisoformat(e["t"])
except (ValueError, KeyError, TypeError):
continue
out.append((run_id, at, str(e.get("kind", ""))[:40], line))
return out
def main(argv) -> int:
dry = "--dry-run" in argv
import pyodbc
conn = pyodbc.connect(cfg.RESULTS_DB_CONN, timeout=15)
cur = conn.cursor()
have = {r[0] for r in cur.execute(
"SELECT DISTINCT run_id FROM dbo.CV_RunEvent").fetchall()}
added_runs = added_rows = 0
for path in sorted(Path(cfg.LOGS).glob(f"{RUN_PREFIX}*.jsonl")):
run_id = path.stem[len(RUN_PREFIX):]
if run_id in have:
continue
rows = rows_of(run_id, path.read_text(encoding="utf-8",
errors="replace"))
if not rows:
continue
added_runs += 1
added_rows += len(rows)
if not dry:
cur.executemany(
"INSERT INTO dbo.CV_RunEvent (run_id, at, kind, body) "
"VALUES (?, ?, ?, ?)", rows)
if not dry:
conn.commit()
conn.close()
verb = "Would add" if dry else "Added"
print(f"{verb} {added_runs} run(s), {added_rows} event(s); "
f"{len(have)} run(s) were already in the table.")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
+17
View File
@@ -104,6 +104,23 @@ BEGIN
END
GO
-- Every Run's events (2026-10-30): the same JSON lines as the bot PC's
-- Logs\events_<run>.jsonl, so the Portal on Dokploy has a Runs page and an
-- Agent run card. Written by the bot (db_datawriter), read by cv_portal
-- (db_datareader). tools/import_run_events.py loads the older files once.
IF OBJECT_ID('dbo.CV_RunEvent', 'U') IS NULL
BEGIN
CREATE TABLE dbo.CV_RunEvent (
id BIGINT IDENTITY(1,1) PRIMARY KEY,
run_id VARCHAR(15) NOT NULL, -- 20261030_101500, the run log's stamp
at DATETIME2(3) NOT NULL,
kind NVARCHAR(40) NOT NULL, -- run_start, claim_start, run_end, ...
body NVARCHAR(MAX) NOT NULL -- the event's JSON line
);
CREATE INDEX IX_CV_RunEvent_run ON dbo.CV_RunEvent (run_id, id);
END
GO
-- So the bot can connect with your Windows login (no password), give that
-- login read/write here. Uncomment and run once, as an admin (e.g. sa):
--