We use gunicorn and gevent in most of our production deployments. There are many options in this area, but this is one we've had great success with and at one point was the fastest based on some benchmarking we did many years ago. (We should re-run that, but that's another blog post).
The Problem
The number of active Redis connections keeps growing. At first glance you would think this would be happening in your Celery workers or even Celery Beat, but it's actually happening in your WSGI (gunicorn) process.
While gevent is given you green threads, Celery isn't aware it's running in a thread safe context so when you call a task in your application code it is creating a NEW connection pool for each task.
In one client's set up this manifested as the connection count growing by 4-5 connections every time a task was called. If things are restarted frequently enough, which happens in a lot of our apps with CI/CD, it goes unnoticed. If however your app runs for weeks on end it's pretty easy to reach the Redis default of 10k connections.
The Solution
You just need to tell Celery it is working in a thread safe environment by setting result_backend_thread_safe = True
.
NOTE: For Django specifically this means added CELERY_RESULT_BACKEND_THREAD_SAFE = True
to your settings.py
.
Once this is set it should properly re-use Redis connections and stop being a problem for you.
Hope this helps!