diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index 52ce5c44..925075ac 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -73,9 +73,14 @@ services: options: max-size: "10m" max-file: "3" + healthcheck: + test: ["CMD", "uv", "run", "worker_health.py"] + timeout: 10s + interval: 30s + start_period: 40s redis: - image: redis:7-alpine + image: redis:8-alpine # ports: # - "127.0.0.1:6379:6379" volumes: diff --git a/backend/run_agent_background.py b/backend/run_agent_background.py index 29b58b5c..e32b5b3b 100644 --- a/backend/run_agent_background.py +++ b/backend/run_agent_background.py @@ -33,7 +33,6 @@ dramatiq.set_broker(rabbitmq_broker) _initialized = False db = DBConnection() -db = DBConnection() workflow_executor = WorkflowExecutor(db) deterministic_executor = DeterministicWorkflowExecutor(db) instance_id = "single" @@ -50,6 +49,11 @@ async def initialize(): _initialized = True logger.info(f"Initialized agent API with instance ID: {instance_id}") +@dramatiq.actor +async def check_health(key: str): + """Run the agent in the background using Redis for state.""" + structlog.contextvars.clear_contextvars() + await redis.set(key, "healthy", ex=redis.REDIS_KEY_TTL) @dramatiq.actor async def run_agent_background( diff --git a/backend/worker_health.py b/backend/worker_health.py new file mode 100644 index 00000000..9f8b610f --- /dev/null +++ b/backend/worker_health.py @@ -0,0 +1,35 @@ +import dotenv +dotenv.load_dotenv() + +from utils.logger import logger +import run_agent_background +from services import redis +import asyncio +from utils.retry import retry +import uuid + + +async def main(): + await retry(lambda: redis.initialize_async()) + key = uuid.uuid4().hex + run_agent_background.check_health.send(key) + timeout = 5 # seconds + elapsed = 0 + while elapsed < timeout: + if await redis.get(key) == "healthy": + break + await asyncio.sleep(1) + elapsed += 1 + + if elapsed >= timeout: + logger.critical("Health check timed out") + exit(1) + else: + logger.critical("Health check passed") + await redis.delete(key) + await redis.close() + exit(0) + + +if __name__ == "__main__": + asyncio.run(main())