Search code examples
flaskcelery

Idle high CPU usage on Celery docker container when deployed with Nginx, Flask and Redis


On idle, the CPU usage of Celery docker container is extremely high with docker stats shows up to 600% usage. This behaviour is observed immediately after starting up the containers before any tasks or requests have been sent to Celery.

This is my run command in the celery docker file

CMD celery -A make_celery worker --pool=gevent --loglevel INFO

This deployment is on a Google Cloud VM with 2vCPU and instance CPU usage fluctuates between 80 and 90%

I have also tried with prefork workers but the behaviour is the same. Also tried to force the celery worker count to 1 and also run the container standalone without the other services.


Solution

  • Found the cause of the high CPU usage by enabling DEBUG logging on the celery instance.

    CMD celery -A make_celery worker --loglevel DEBUG
    

    There were an unusual number of ping calls which lead to checking the healthcheck configured in docker compose.

    [DEBUG/MainProcess] pidbox received method ping() [reply_to:{'exchange': 'reply.celery.pidbox', 'routing_key': '********'} ticket:********]
    

    Inside my docker compose I had

      celery_worker:
        build:
          context: .
          dockerfile: ./docker/prod/celery.Dockerfile
        image: [repo/image]
        healthcheck:
          test: celery -A make_celery inspect ping
          interval: 1s     <-------------
          timeout: 5s
          retries: 10
        env_file:
          - .env
        depends_on:
          - redis
        networks:
          - app-network
        restart: unless-stopped
    

    Due to how the celery health check works, it creates new worker to run the ping command. However due to the 1 second interval it would keep creating a new worker immediately consecutively.

    Changing this to a less frequent interval immediately reduced the CPU load.

      celery_worker:
        build:
          context: .
          dockerfile: ./docker/prod/celery.Dockerfile
        image: [repo/image]
        healthcheck:
          test: celery -A make_celery inspect ping
          interval: 60s
          timeout: 5s
          retries: 5
        env_file:
          - .env
        depends_on:
          - redis
        networks:
          - app-network
        restart: unless-stopped