implement job runner and scheduler
This commit is contained in:
parent
328a70ff9b
commit
2b2a3f1cc0
11 changed files with 1572 additions and 284 deletions
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
|
||||
import htpy as h
|
||||
from htpy import Node, Renderable
|
||||
|
||||
|
|
@ -12,36 +14,43 @@ from repub.components import (
|
|||
stat_card,
|
||||
status_badge,
|
||||
)
|
||||
from repub.pages.runs import RUNNING_EXECUTIONS
|
||||
|
||||
|
||||
def _running_execution_row(execution: dict[str, str | bool]) -> tuple[Node, ...]:
|
||||
status_tone = "running" if execution["is_running"] else "done"
|
||||
def _text(values: Mapping[str, object], key: str) -> str:
|
||||
return str(values[key])
|
||||
|
||||
|
||||
def _running_execution_row(execution: Mapping[str, object]) -> tuple[Node, ...]:
|
||||
status_tone = "running" if _text(execution, "status") != "Succeeded" else "done"
|
||||
return (
|
||||
h.div[
|
||||
h.div(class_="font-semibold text-slate-950")[execution["source"]],
|
||||
h.div(class_="font-semibold text-slate-950")[_text(execution, "source")],
|
||||
h.p(class_="mt-0.5 font-mono text-[11px] text-slate-500")[
|
||||
execution["slug"]
|
||||
_text(execution, "slug")
|
||||
],
|
||||
],
|
||||
h.div[
|
||||
h.p(class_="font-medium text-slate-900")[f"#{execution['execution_id']}"],
|
||||
h.p(class_="font-medium text-slate-900")[
|
||||
f"#{_text(execution, 'execution_id')}"
|
||||
],
|
||||
h.p(class_="mt-0.5 text-[11px] text-slate-500")[
|
||||
f"job {execution['job_id']}"
|
||||
f"job {_text(execution, 'job_id')}"
|
||||
],
|
||||
],
|
||||
h.div[
|
||||
h.p(class_="font-medium text-slate-900")[execution["started_at"]],
|
||||
h.p(class_="mt-0.5 text-[11px] text-slate-500")[execution["runtime"]],
|
||||
h.p(class_="font-medium text-slate-900")[_text(execution, "started_at")],
|
||||
h.p(class_="mt-0.5 text-[11px] text-slate-500")[
|
||||
_text(execution, "runtime")
|
||||
],
|
||||
],
|
||||
status_badge(label=str(execution["status"]), tone=status_tone),
|
||||
status_badge(label=_text(execution, "status"), tone=status_tone),
|
||||
h.div(class_="min-w-56 whitespace-normal")[
|
||||
h.p(class_="font-medium text-slate-900")[execution["stats"]],
|
||||
h.p(class_="mt-0.5 text-[11px] text-slate-500")[execution["worker"]],
|
||||
h.p(class_="font-medium text-slate-900")[_text(execution, "stats")],
|
||||
h.p(class_="mt-0.5 text-[11px] text-slate-500")[_text(execution, "worker")],
|
||||
],
|
||||
h.div(class_="flex flex-nowrap items-center gap-3")[
|
||||
inline_link(
|
||||
href=str(execution["log_href"]),
|
||||
href=_text(execution, "log_href"),
|
||||
label="View log",
|
||||
tone="amber",
|
||||
),
|
||||
|
|
@ -71,7 +80,13 @@ def dashboard_header() -> Renderable:
|
|||
]
|
||||
|
||||
|
||||
def operational_snapshot() -> Renderable:
|
||||
def operational_snapshot(*, snapshot: Mapping[str, str] | None = None) -> Renderable:
|
||||
values = snapshot or {
|
||||
"running_now": "0",
|
||||
"upcoming_today": "0",
|
||||
"failures_24h": "0",
|
||||
"artifact_footprint": "0 B",
|
||||
}
|
||||
return h.section[
|
||||
h.div(class_="mb-3 flex items-end justify-between gap-4")[
|
||||
h.div[
|
||||
|
|
@ -82,37 +97,39 @@ def operational_snapshot() -> Renderable:
|
|||
"Operational snapshot"
|
||||
],
|
||||
],
|
||||
h.p(class_="text-xs text-slate-500")[
|
||||
"Static fixture data shaped around the intended operator dashboard"
|
||||
],
|
||||
h.p(class_="text-xs text-slate-500")["Live values from the database"],
|
||||
],
|
||||
h.dl(class_="grid gap-3 md:grid-cols-2 xl:grid-cols-4")[
|
||||
stat_card(
|
||||
label="Running now",
|
||||
value="3",
|
||||
detail="Two feed workers and one Pangea worker are active.",
|
||||
value=values["running_now"],
|
||||
detail="Currently active job executions.",
|
||||
),
|
||||
stat_card(
|
||||
label="Upcoming today",
|
||||
value="11",
|
||||
detail="Next scheduled job fires in 13 minutes.",
|
||||
value=values["upcoming_today"],
|
||||
detail="Enabled jobs that are ready for their next run.",
|
||||
),
|
||||
stat_card(
|
||||
label="Failures in 24h",
|
||||
value="2",
|
||||
detail="One network timeout and one source parsing error.",
|
||||
value=values["failures_24h"],
|
||||
detail="Recent failed executions recorded by the scheduler.",
|
||||
),
|
||||
stat_card(
|
||||
label="Output footprint",
|
||||
value="18.4 GB",
|
||||
detail="Mirrored feeds, media, logs, and execution stats.",
|
||||
label="Artifact footprint",
|
||||
value=values["artifact_footprint"],
|
||||
detail="Current log and stats artifact size under out/logs.",
|
||||
),
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
def running_executions_table() -> Renderable:
|
||||
rows = tuple(_running_execution_row(execution) for execution in RUNNING_EXECUTIONS)
|
||||
def running_executions_table(
|
||||
*, running_executions: tuple[Mapping[str, object], ...] | None = None
|
||||
) -> Renderable:
|
||||
rows = tuple(
|
||||
_running_execution_row(execution) for execution in (running_executions or ())
|
||||
)
|
||||
headers = ("Source", "Execution", "Started", "Status", "Stats", "Actions")
|
||||
|
||||
def render_row(row: tuple[Node, ...]) -> Renderable:
|
||||
|
|
@ -172,6 +189,14 @@ def running_executions_table() -> Renderable:
|
|||
|
||||
|
||||
def dashboard_page() -> Renderable:
|
||||
return dashboard_page_with_data()
|
||||
|
||||
|
||||
def dashboard_page_with_data(
|
||||
*,
|
||||
snapshot: Mapping[str, str] | None = None,
|
||||
running_executions: tuple[Mapping[str, object], ...] | None = None,
|
||||
) -> Renderable:
|
||||
return h.main(
|
||||
id="morph",
|
||||
class_="min-h-screen lg:grid lg:grid-cols-[18rem_minmax(0,1fr)]",
|
||||
|
|
@ -180,8 +205,8 @@ def dashboard_page() -> Renderable:
|
|||
h.div(class_="px-4 py-4 sm:px-5 lg:px-6 lg:py-5")[
|
||||
h.div(class_="mx-auto max-w-7xl space-y-5")[
|
||||
dashboard_header(),
|
||||
operational_snapshot(),
|
||||
running_executions_table(),
|
||||
operational_snapshot(snapshot=snapshot),
|
||||
running_executions_table(running_executions=running_executions),
|
||||
]
|
||||
],
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue