feat(agent): scheduler, healthcheck, and container entrypoint

This commit is contained in:
2026-08-23 17:13:18 -05:00
parent 1877efdbde
commit 43add3b0fe
4 changed files with 113 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
"""Agent entrypoint: bootstrap the database, then run scheduled jobs forever."""
from __future__ import annotations
import logging
from agent import __version__
from agent.config import load_config
from agent.db import ensure_database, run_migrations
from agent.jobs.heartbeat import run_heartbeat
from agent.scheduler import build_scheduler
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = logging.getLogger("agent")
def main() -> None:
logger.info("firefly-agent %s starting", __version__)
cfg = load_config()
ensure_database(cfg)
applied = run_migrations(cfg)
if applied:
logger.info("applied migrations: %s", ", ".join(applied))
status = run_heartbeat(cfg)
logger.info("startup heartbeat: %s", status)
logger.info(
"scheduler starting; heartbeat every %d minutes",
cfg.heartbeat_interval_minutes,
)
build_scheduler(cfg).start()
if __name__ == "__main__":
main()
+23
View File
@@ -0,0 +1,23 @@
"""Docker HEALTHCHECK entry: healthy = agentdb answers SELECT 1."""
from __future__ import annotations
import sys
from agent.config import load_config
from agent.db import connect
def main() -> int:
try:
cfg = load_config()
with connect(cfg) as conn:
conn.execute("SELECT 1")
return 0
except Exception as exc:
print(f"unhealthy: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
+23
View File
@@ -0,0 +1,23 @@
"""APScheduler assembly: one place where jobs get registered."""
from __future__ import annotations
from apscheduler.schedulers.base import BaseScheduler
from apscheduler.schedulers.blocking import BlockingScheduler
from agent.config import AgentConfig
from agent.jobs.heartbeat import run_heartbeat
def build_scheduler(
cfg: AgentConfig, *, scheduler_class: type = BlockingScheduler
) -> BaseScheduler:
scheduler = scheduler_class(timezone="UTC")
scheduler.add_job(
run_heartbeat,
"interval",
args=[cfg],
minutes=cfg.heartbeat_interval_minutes,
id="heartbeat",
)
return scheduler
+30
View File
@@ -0,0 +1,30 @@
from datetime import timedelta
from apscheduler.schedulers.background import BackgroundScheduler
from agent.config import AgentConfig
from agent.scheduler import build_scheduler
def _cfg(minutes: int) -> AgentConfig:
return AgentConfig(
db_host="db",
db_port=5432,
db_user="u",
db_password="p",
agent_db_name="agentdb",
firefly_url="http://app:8080",
firefly_token="tok",
heartbeat_interval_minutes=minutes,
)
def test_build_scheduler_registers_heartbeat_at_configured_interval():
scheduler = build_scheduler(_cfg(minutes=15), scheduler_class=BackgroundScheduler)
scheduler.start(paused=True)
try:
job = scheduler.get_job("heartbeat")
assert job is not None
assert job.trigger.interval == timedelta(minutes=15)
finally:
scheduler.shutdown(wait=False)