Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Background callbacks not working on iOS/iPhone and Safari #3123

Open
celia-lm opened this issue Jan 15, 2025 · 0 comments
Open

Background callbacks not working on iOS/iPhone and Safari #3123

celia-lm opened this issue Jan 15, 2025 · 0 comments
Labels
bug something broken cs customer success P2 considered for next cycle

Comments

@celia-lm
Copy link

[workaround and code to reproduce the issue at the end of this message]

Screen.Recording.2025-01-15.at.14.22.34.mov

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 running and/or cancel arguments.
  • 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
@gvwilson gvwilson added bug something broken P2 considered for next cycle cs customer success labels Jan 15, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug something broken cs customer success P2 considered for next cycle
Projects
None yet
Development

No branches or pull requests

2 participants