90 lines
2.0 KiB
Python
90 lines
2.0 KiB
Python
from datetime import datetime, timedelta, timezone
|
|
|
|
from app.db.database import get_connection
|
|
from app.db.migrations import run_migrations
|
|
|
|
|
|
def parse_timestamp(value: str | None) -> datetime | None:
|
|
if not value:
|
|
return None
|
|
|
|
normalized = value.strip().replace("Z", "+00:00")
|
|
formats = [
|
|
"%Y-%m-%d %H:%M:%S",
|
|
"%Y-%m-%d %H:%M:%S.%f",
|
|
"%Y-%m-%dT%H:%M:%S",
|
|
"%Y-%m-%dT%H:%M:%S.%f",
|
|
]
|
|
|
|
try:
|
|
parsed = datetime.fromisoformat(normalized)
|
|
return parsed.astimezone(timezone.utc).replace(tzinfo=None) if parsed.tzinfo else parsed
|
|
except ValueError:
|
|
pass
|
|
|
|
for fmt in formats:
|
|
try:
|
|
return datetime.strptime(normalized, fmt)
|
|
except ValueError:
|
|
continue
|
|
|
|
return None
|
|
|
|
|
|
def is_worker_online(last_seen_at: str | None) -> bool:
|
|
last_seen = parse_timestamp(last_seen_at)
|
|
if not last_seen:
|
|
return False
|
|
|
|
return last_seen >= datetime.utcnow() - timedelta(seconds=30)
|
|
|
|
|
|
def with_online_status(worker: dict):
|
|
worker["online"] = is_worker_online(worker.get("last_seen_at"))
|
|
return worker
|
|
|
|
|
|
def get_workers():
|
|
run_migrations()
|
|
con = get_connection()
|
|
|
|
rows = con.execute(
|
|
"""
|
|
SELECT
|
|
worker_id,
|
|
status,
|
|
last_seen_at,
|
|
current_job_id,
|
|
started_at,
|
|
metadata_json
|
|
FROM workers
|
|
ORDER BY worker_id
|
|
"""
|
|
).fetchall()
|
|
|
|
con.close()
|
|
return [with_online_status(dict(row)) for row in rows]
|
|
|
|
|
|
def get_worker(worker_id: str):
|
|
run_migrations()
|
|
con = get_connection()
|
|
|
|
row = con.execute(
|
|
"""
|
|
SELECT
|
|
worker_id,
|
|
status,
|
|
last_seen_at,
|
|
current_job_id,
|
|
started_at,
|
|
metadata_json
|
|
FROM workers
|
|
WHERE worker_id = ?
|
|
""",
|
|
(worker_id,),
|
|
).fetchone()
|
|
|
|
con.close()
|
|
return with_online_status(dict(row)) if row else None
|