Fix missing run start time and add duration to run history
create_run now sets started_at on INSERT. list_runs computes duration_s via julianday arithmetic. Both the module detail and runs page show duration formatted as Xs or Xm Ys. A Jinja2 filter handles formatting. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
595024eb52
commit
f39b1df75e
@ -404,7 +404,8 @@ def clear_stale_locks(max_age_hours: int = 24, live_pids: set[int] | None = None
|
||||
def create_run(module_id: int, *, group_run_id: int | None = None) -> int:
|
||||
with db.connect() as c:
|
||||
cur = c.execute(
|
||||
"INSERT INTO run_log (module_id, group_run_id) VALUES (?, ?)",
|
||||
"INSERT INTO run_log (module_id, group_run_id, started_at) "
|
||||
"VALUES (?, ?, datetime('now'))",
|
||||
(module_id, group_run_id),
|
||||
)
|
||||
return int(cur.lastrowid)
|
||||
@ -494,6 +495,10 @@ def list_runs(*, module_id: int | None = None, status: str | None = None,
|
||||
params.append(limit)
|
||||
with db.connect() as c:
|
||||
return [dict(r) for r in c.execute(
|
||||
f"SELECT r.*, m.name AS module_name FROM run_log r "
|
||||
f"SELECT r.*, m.name AS module_name, "
|
||||
f"CASE WHEN r.started_at IS NOT NULL AND r.finished_at IS NOT NULL "
|
||||
f"THEN CAST(ROUND((julianday(r.finished_at) - julianday(r.started_at)) * 86400) AS INTEGER) "
|
||||
f"ELSE NULL END AS duration_s "
|
||||
f"FROM run_log r "
|
||||
f"LEFT JOIN module m ON r.module_id=m.id "
|
||||
f"{clause} ORDER BY r.id DESC LIMIT ?", params)]
|
||||
|
||||
@ -29,6 +29,18 @@ _WEB_DIR = Path(__file__).parent
|
||||
_templates = Jinja2Templates(directory=_WEB_DIR / "templates")
|
||||
|
||||
|
||||
def _fmt_duration(seconds) -> str:
|
||||
if seconds is None:
|
||||
return "—"
|
||||
s = int(seconds)
|
||||
if s < 60:
|
||||
return f"{s}s"
|
||||
return f"{s // 60}m {s % 60:02d}s"
|
||||
|
||||
|
||||
_templates.env.filters["duration"] = _fmt_duration
|
||||
|
||||
|
||||
def mount_web(app: FastAPI) -> None:
|
||||
"""Attach HTML pages + /static onto a FastAPI app."""
|
||||
app.mount("/static", StaticFiles(directory=_WEB_DIR / "static"), name="static")
|
||||
|
||||
@ -187,12 +187,13 @@
|
||||
<div class="body tight">
|
||||
{% if recent_runs %}
|
||||
<table class="grid">
|
||||
<thead><tr><th>id</th><th>started</th><th>status</th><th>rows</th></tr></thead>
|
||||
<thead><tr><th>id</th><th>started</th><th>duration</th><th>status</th><th>rows</th></tr></thead>
|
||||
<tbody>
|
||||
{% for r in recent_runs %}
|
||||
<tr>
|
||||
<td><a href="/runs/{{ r.id }}">#{{ r.id }}</a></td>
|
||||
<td class="mono">{{ r.started_at }}</td>
|
||||
<td class="mono">{{ r.started_at or '—' }}</td>
|
||||
<td class="mono">{{ r.duration_s | duration }}</td>
|
||||
<td><span class="pill {{ r.status }}">{{ r.status }}</span></td>
|
||||
<td class="mono">{{ r.row_count if r.row_count is not none else "—" }}</td>
|
||||
</tr>
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<th style="width:5em">id</th>
|
||||
<th>module</th>
|
||||
<th>started</th>
|
||||
<th>finished</th>
|
||||
<th>duration</th>
|
||||
<th style="width:8em">status</th>
|
||||
<th style="width:7em">rows</th>
|
||||
<th>error</th>
|
||||
@ -33,8 +33,8 @@
|
||||
<tr>
|
||||
<td><a href="/runs/{{ r.id }}">#{{ r.id }}</a></td>
|
||||
<td><a href="/modules/{{ r.module_id }}">{{ r.module_name }}</a></td>
|
||||
<td class="mono">{{ r.started_at }}</td>
|
||||
<td class="mono">{{ r.finished_at or '—' }}</td>
|
||||
<td class="mono">{{ r.started_at or '—' }}</td>
|
||||
<td class="mono">{{ r.duration_s | duration }}</td>
|
||||
<td><span class="pill {{ r.status }}">{{ r.status }}</span></td>
|
||||
<td class="mono">{{ r.row_count if r.row_count is not none else "—" }}</td>
|
||||
<td class="mono" style="max-width:22rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ r.error or '' }}</td>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user