Background callbacks with celery + redis getting 204s
Wally110 opened this issue · comments
My dash app uses background callbacks with Celery and Redis for long-running requests. It's being tested in Dev container.
Issue
I'm getting 204s intermittently when triggering the background callback. Sometimes the callback and caching work. Sometimes the dash/_dash-update-component endpoint just returns 204, and nothing on the frontend gets updated.
Below is the gunicorn log
![image](https://private-user-images.githubusercontent.com/18901936/314923967-09cededc-cf6a-4f22-aae8-124584c511a4.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MTg5MzI2MTMsIm5iZiI6MTcxODkzMjMxMywicGF0aCI6Ii8xODkwMTkzNi8zMTQ5MjM5NjctMDljZWRlZGMtY2Y2YS00ZjIyLWFhZTgtMTI0NTg0YzUxMWE0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA2MjElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwNjIxVDAxMTE1M1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTcwMjE4NGI1NjUxYTgwYWVhMGEwNzJmOTdkZWQzODExMDA4MzA1ZjhjZmViYWQ2MDM5ZDFmMzVkZDYyMjQzOWMmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.p8Ut0H1bogXnIgnnpuWMBOiB73GqJQOCeiFPZRY46bc)
Basic code structure
main.py
redis_conn_str = "..."
app_celery = Celery(__name__, broker=redis_conn_str, backend=redis_conn_str)
background_callback_manager = CeleryManager(app_celery, expire=1200)
app_server = Flask(__name__)
app = Dash(
__name__,
use_pages=True,
suppress_callback_exceptions=True,
server=app_server,
background_callback_manager=background_callback_manager,
)
run_server.sh
nohup celery -A app.app_celery worker --loglevel=INFO -c 2 | tee /dev/null &
gunicorn --bind=0.0.0.0:8000 --workers=2 --worker-class=gthread --threads=20 app:app_server
callbacks.py
...
register_page(__name__, path="/dashboard")
layout = html.Div(...)
@callback(
Output("output1", "data"),
Output("output2", "children"),
[
Input("button", "n_clicks"),
State("date-picker-range", "start_date"),
State("date-picker-range", "end_date"),
State("start1", "value"),
State("start1", "value"),
State("start1", "value"),
... # 12 states in total
],
prevent_initial_call=True,
background=True,
cache_args_to_ignore=[0],
interval=9000,
)
def run_sql_query_callback(...):
...
return dcc.send_data_frame(res.to_csv, "result.csv"), None
I've tried everything I can to debug, but it doesn't work. So, I need your help here. Much appreciate.
Issue resolved.
The root cause is that the same Celery queue is used by multiple versions of running dash instances, which causes a task submitted by a producer to be consumed by a worker of a different version.
A better practice is to use different queues for different versions of workers.