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:
1 parent
d500f750da
commit
840272032a
9 files changed
+655
-46
No files matched your search
@@ -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:]))
|
||||
@@ -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):
|
||||
--
|
||||
|
||||
Reference in new issue
Block a user