37

I know one of the ways to check health for Docker container is using the commmand

HEALTHCHECK CMD curl --fail http://localhost:3000/ || exit 1

But in case of workers there is no such URL to hit , How to check the container's health in that case ?

Tzvika Mordoch
  • 191
  • 2
  • 13
Always_Beginner
  • 2,546
  • 6
  • 25
  • 33

6 Answers6

35

The celery inspect ping command comes in handy, as it does a whole trip: it sends a "ping" task on the broker, workers respond and celery fetches the responses.

Assuming your app is named tasks.add, you may ping all your workers:

/app $ celery inspect ping -A tasks.add
-> celery@aa7c21dd0e96: OK
        pong
-> celery@57615db15d80: OK
        pong

With aa7c21dd0e96 being the Docker hostname, and thus available in $HOSTNAME.

To ping a single node, you would have to run:

celery inspect ping -A tasks.add -d celery@$HOSTNAME

Here, d stands for destination.

The line to add to your Dockerfile:

HEALTHCHECK CMD celery inspect ping -A tasks.add -d celery@$HOSTNAME

Sample outputs:

/app $ celery inspect ping -A tasks.add -d fake_node
Error: No nodes replied within time constraint.
/app $ echo $?
69

Unhealthy if the node does not exist or does not reply

/app $ celery inspect ping -A tasks.add -d celery@$HOSTNAME
-> celery@d39b3d31cc13: OK
        pong
/app $ echo $?
0

Healthy when the node replies pong.

/app $ celery inspect ping -d celery@$HOSTNAME
Traceback (most recent call last):
...
    raise socket.error(last_err)
OSError: [Errno 111] Connection refused
/app $ echo $?
1

Unhealthy when the broker is not available - I removed the app, so it tries to connect to a local AMPQ and fails This might not suit your needs, the broker is unhealthy, not the worker.

punkeel
  • 869
  • 8
  • 12
  • 6
    with SQS, how do you do? you can't use the result with sqs and celery http://docs.celeryproject.org/en/master/getting-started/brokers/sqs.html#broker-sqs – EsseTi Jun 25 '18 at 12:05
  • 1
    I believe "Assuming your app is named tasks.add" it's a confusing assumption: an app should not live in a module named `tasks`, if you want to minimize confusion. – silviot Apr 20 '20 at 09:50
  • 2
    For SQS, you can specify the pidfile using `--pidfile /opt/celery/celery_pid` and check that the process is still running using `kill -0 $(cat /opt/celery/celery_pid)`. Got this from the guy that runs masterpoint.io. – SomeGuyOnAComputer May 27 '20 at 21:26
  • 1
    @SomeGuyOnAComputer nice tip on using `kill -0` thanks! – pangyuteng Apr 16 '22 at 20:22
9

The below example snippet, derived from that posted by @PunKeel, is applicable for those looking to implement health check in docker-compose.yml which could be used through docker-compose or docker stack deploy.

worker:
    build:
        context: .
        dockerfile: Dockerfile
    image: myimage
    links:
        - rabbitmq
    restart: always
    command: celery worker --hostname=%h --broker=amqp://rabbitmq:5672
    healthcheck:
        test: celery -b amqp://rabbitmq:5672 inspect ping -d celery@$$HOSTNAME
        interval: 30s
        timeout: 10s
        retries: 3

Notice the extra $ in the command, so that $HOSTNAME actually gets passed into the container. I also didn't use the -A flag.

Ideally, rabbitmq should also have its own health check, perhaps with curl guest:guest@localhost:15672/api/overview, since docker wouldn't be able to discern if worker is down or the broker is down with celery inspect ping.

pangyuteng
  • 1,749
  • 14
  • 29
  • 1
    In case you are using authentication, you can provide username and password by writing `user:pass@rabbitmq:5672`. You can even use environment variables you set yourself for your application like, `celery inspect ping -b amqp://$${RABBITMQ_USER}:$${RABBITMQ_PASS}@$${RABBITMQ_HOST}:5672 -d celery@$$HOSTNAME` – luckydonald Mar 25 '21 at 16:29
  • On Celery 5.2.3: `Error: No such option: -b` – Martin Thoma Mar 02 '22 at 08:41
  • 2
    The order needs to be changed: `celery -b amqp://rabbitmq:5672 inspect ping` – Martin Thoma Mar 02 '22 at 08:47
  • updated healthheck test command per @Mart! – pangyuteng Jun 10 '22 at 23:11
2

For celery 5.2.3 I used celery -A [celery app name] status for the health check. This is how my docker-compose file looks like

worker:
      build: .
      healthcheck:
        test: celery -A app.celery_app status
        interval: 10s
        timeout: 10s
        retries: 10
      volumes:
          - ./app:/app
      depends_on:
        - broker
        - redis
        - database
0

Landed on this question looking for a health check for Celery workers as part of an Airflow setup (Airflow 2.3.4, Celery 5.2.7), which I eventually figured out. This is a very specific use case of the original question, but might still be useful for some:

# docker-compose.yml

  worker:
      image: ...
      hostname: local-worker
      entrypoint: airflow celery worker
      ...
      healthcheck:
        test: [ "CMD-SHELL", 'celery --app airflow.executors.celery_executor.app inspect ping -d "celery@$${HOSTNAME}"' ]
        interval: 5s
        timeout: 10s
        retries: 10
      restart: always
      ...

I got inspiration from Airflow's quick-start Docker Compose.

swimmer
  • 1,971
  • 2
  • 17
  • 28
0

As simple as that:

...
healthcheck:
    test: sh -c 'celery -A your_celery_module inspect ping'
    ...

Your log file will have a similar ping log:

[2023-05-05 11:18:47,309: DEBUG/MainProcess] pidbox received method ping() [reply_to:{'exchange': 'reply.celery.pidbox', 'routing_key': '8195241f-122a-3dc4-9841-739f55804b82'} ticket:bada7609-ce6b-499a-b3c2-c80911e0fe09]

Also, you might want to check it yourself in an already-running container. In that case, it will look something like this:

celery ping output

Taras Mykhalchuk
  • 829
  • 1
  • 9
  • 20
0

To configure a HEALTHCHECK for a Docker container running Celery tasks and ensure another container depends on its health status:

In your Docker Compose file:

version: "3.8"
services:
  celery:
    # Celery container config
    healthcheck:
      test: celery inspect ping
      interval: 1m
      timeout: 10s
      retries: 10
      start_period: 1m

  dependent_container:
    # Dependent container config
    depends_on:
      celery:
        condition: service_healthy

This sets up a health check for the celery container using celery inspect ping.
The dependent_container depends on celery with condition: service_healthy, ensuring it starts only when celery is healthy.

chethan
  • 115
  • 10