Background callbacks not working on iOS/iPhone and Safari
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.4k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 13
Description
[workaround and code to reproduce the issue at the end of this message]
https://github.com/user-attachments/assets/71d085f6-1377-4559-abca-0e34d720facd
Text of the error:
[Error] Failed to load resource: The network connection was lost. (_dash-update-component, line 0)
[Error] Error: Callback failed: the server did not respond.
g — dash_renderer.v2_18_2m1736947227.min.js:2:145898
So (dash_renderer.v2_18_2m1736947227.min.js:2:95216)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:103633)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:206857)
p (dash_renderer.v2_18_2m1736947227.min.js:2:42868)
Yi (dash_renderer.v2_18_2m1736947227.min.js:2:115653)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:160719)
forEach
observer (dash_renderer.v2_18_2m1736947227.min.js:2:157858)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:105928)
forEach
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:105879)
p (dash_renderer.v2_18_2m1736947227.min.js:2:42928)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:170393)
f (dash_renderer.v2_18_2m1736947227.min.js:2:161605)
(anonymous function) (dash_renderer.v2_18_2m1736947227.min.js:2:162948)
$u (dash_renderer.v2_18_2m1736947227.min.js:2:168505)
a (dash_renderer.v2_18_2m1736947227.min.js:2:170597)
The issue is intermittent: it's possible that some of the requests/clicks work, but typically if the first one hasn't worked, none of them will.
Information about the video:
- MacBook Ait M3 macOS 14.6.1
- Safari 17.6
- App deployed to Dash Enterprise 4 > I'm not sure if this happens on DE5 or not. I remember replicating it on DE5 this morning but now the same code doesn't cause the issue on DE5.
Things I have not tested:
- If the issue happens locally.
Things I have tested:
The issue still happens:
- If the background callback uses the
runningand/orcancelarguments. - If we use previous versions of Dash (tested from 2.13 to 2.18).
- The user accesses the app from a Safari incognito window.
Workaround
- Add a dcc.Interval to the layout with a quite frequent refresh rate (I've used interval=200, that is, 200ms > a higher value might work).
- Create a callback that uses that interval as Input. It can have no output and return nothing, like this:
@callback(Input("interval_dummy", "n_intervals"))
def dummycb(_):
return
- Since this workaround will make a callback run every 200ms, the tab name will constantly show "Updating...". You can disable this by specifying updating_title=None as an argument to app = Dash().
Code to reproduce the issue
- Deploy the app.
- Access it from Safari.
- Open the Inspect window.
- Click the "Run" button.
requirements.txt
celery
dash
gunicorn
redis
at the time of creation of this ticket, these are the versions my app uses:
- celery 5.4.0
- dash 2.18.2
- gunicorn 23.0.0
- redis 5.2.1
app.py
import time
import os
import datetime
import dash
from dash import Dash, CeleryManager
from dash import Input, Output, State, ctx, html, dcc, callback #, set_props
from celery import Celery
celery_app = Celery(__name__, broker=f"{os.environ['REDIS_URL']}/5", backend=f"{os.environ['REDIS_URL']}/6")
background_callback_manager = CeleryManager(celery_app)
app = Dash()
server = app.server
app.layout = html.Div(
[
html.Div([html.P(id="paragraph_id", children=["Button not clicked"])]),
html.Button(id="button_id", children="Run Job!"),
html.Button(id="cancel_button_id", children="Cancel Running Job!"),
# dcc.Interval(id="interval_dummy", interval=200),
]
)
@callback(
output=Output("paragraph_id", "children"),
inputs=Input("button_id", "n_clicks"),
background=True,
manager=background_callback_manager
)
def update_clicks(n_clicks):
time.sleep(2.0)
return [f"Clicked {n_clicks} times"]
# @callback(
# Input("interval_dummy", "n_intervals")
# )
# def dummycb(_):
# return
if __name__ == "__main__":
app.run(debug=True)
Procfile
web: gunicorn app:server --workers 4
worker: celery -A app:celery_app worker --loglevel=INFO --concurrency=2
DOKKU_SCALE
web=1
worker=1
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction in app.py and the deployment configuration in Procfile and DOKKU_SCALE. Deploy the supplied Celery-backed background callback app, then run it in Safari with the Inspect window open and compare the failing callback with the documented dcc.Interval workaround. Done means background callbacks work reliably without requiring the workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, redis
- Domain
- backend, devops, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100