# BlockingCallbackTransform

**URL:** <https://community.plotly.com/t/blockingcallbacktransform/60752>\
**Category:** Dash Python\
**Tags:** show-and-tell, tips-and-tricks\
**Created:** [February 6, 2022, 8:23am UTC](https://community.plotly.com/t/blockingcallbacktransform/60752 "2022-02-06T08:23:42Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Emil](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emil/32/31734_2.png) [@Emil](https://community.plotly.com/u/Emil)\
**Post date:** [February 6, 2022, 8:23am UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/1 "2022-02-06T08:23:42Z")

</div>

Once in a while, I hit the issue that a callback is invoked (again) before the previous invocation has completed. The most typical case is pulling updates using the `Interval` component. If the update itself takes longer than the polling interval (e.g. due to a slow database), the callback will never complete. Here is a small example,

```auto
import time
from dash_extensions.enrich import DashProxy, dcc, html, Output, Input

app = DashProxy()
app.layout = html.Div([html.Div(id="output"), dcc.Interval(id="trigger")]) # default interval is 1s

@app.callback(Output("output", "children"), Input("trigger", "n_intervals"), blocking=True)
def update(n_intervals):
    time.sleep(5) # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"

if __name__ == ' __main__':
    app.run_server()

```

in which the “output.children” element will _never_ be updated due to this issue. What I would have _wanted_ to happen was for the callback to run until completed, even if the trigger fires again before that happens. So far, I haven’t fount any good solutions (but please let me know, if you found one), so I decided to create a `BlockingCallbackTransform`. It’s introduced in `dash-extensions==0.0.69` and can be used like this,

```auto
import time
from dash_extensions.enrich import DashProxy, dcc, html, Output, Input, BlockingCallbackTransform

app = DashProxy(transforms=[BlockingCallbackTransform(timeout=10)])
app.layout = html.Div([html.Div(id="output"), dcc.Interval(id="trigger")]) # default interval is 1s

@app.callback(Output("output", "children"), Input("trigger", "n_intervals"), blocking=True)
def update(n_intervals):
    time.sleep(5) # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"

if __name__ == ' __main__':
    app.run_server()

```

The client will now wait until the callback is completed (or the timeout is exceeded) before invoking it again. Hence the app will now “work” (i.e. the hello-message will actually be displayed). I figured this approach might be of help to others 🙂

---

<div class="post-metadata">

**Author:** ![adamschroeder](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/adamschroeder/32/17280_2.png) [@adamschroeder](https://community.plotly.com/u/adamschroeder)\
**Post date:** [February 8, 2022, 6:16pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/2 "2022-02-08T18:16:08Z")

</div>

@Emil ,  
Thank you for creating and sharing about `BlockingCallbackTransform()`. I’ve had this mentioned to me a few times by community members, and I’ve also encountered this issue in one of my apps. This is really helpful.

Let’s say that we use `blocking=True` in the first callback within an app with chained callbacks. Would it be correct to assume that the second callback will trigger only after the first callback timeout is exceeded (or once callback is completed)?

---

<div class="post-metadata">

**Author:** ![Emil](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emil/32/31734_2.png) [@Emil](https://community.plotly.com/u/Emil)\
**Post date:** [February 8, 2022, 7:27pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/3 "2022-02-08T19:27:25Z")

</div>

Thanks! Assuming that the second callback is only triggered by the output of the first callback, then I believe the answer is yes.

---

<div class="post-metadata">

**Author:** ![MarinaZaitseva](https://avatars.discourse-cdn.com/v4/letter/m/85e7bf/32.png) [@MarinaZaitseva](https://community.plotly.com/u/MarinaZaitseva)\
**Post date:** [August 11, 2024, 9:55am UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/4 "2024-08-11T09:55:06Z")

</div>

![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/e/8/e83db035db7f0ef1dc793e32db2eb4824023fcfc.jpeg)  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/b/1/b1ad3a9db6fcd181534d5c2aa78fd302e874f43b.png)  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/6/e/6ea570593e3e5cf8a7ac53e24757a6fcb65ad145.png)

Thank You for very useful BlockingCallbackTransform(). I tried to use it for my MultiPage application, but found a problem, which cannot solve myself.

In the app.py – @app.callback is OK, as in Your example. I can see a changing “Test1 n\_intervals is \_\_” in the window of browser.

In my Page1.py - @callback does not work at all (as I thought at first). I couldn’t see a “Test2 n\_intervals is \_\_” , which should clone Test1 in the window of browser.

But occasionally I noticed, that sometimes it works, but by some unknown way. And now I understood that it works, but can’t show result the right way in the window of browser (Google Chrome, Microsoft Edge).

If I minimize a window with “Test1 n\_intervals is \_\_” for some seconds, and reopen it – I can see a both strings:

“Test1 n\_intervals is \_\_”

“Test2 n\_intervals is \_\_”

But Test1 keeps changing, and Test2 – stays freezing with some fixed number

Same result can be, if I put some application on top of my app window and then remove it – Test2 will be changed once again.

My problem is - “Test2 n\_intervals is \_\_” is not changing now in a real-time. Could you fix this problem, or maybe recommend me to change something in my code, that I could use BlockingCallbackTransform() in MultiPage mode of my application ?

**app.py**

```auto
import time, dash 
from dash_extensions.enrich import DashProxy, dcc, html, Output, Input, BlockingCallbackTransform
import dash_bootstrap_components as dbc # pip install dash-bootstrap-components

FONT_AWESOME = ("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css")
app = DashProxy(
    __name__ , suppress_callback_exceptions=True, 
    transforms=[BlockingCallbackTransform(timeout=10)],
    external_stylesheets=[dbc.themes.BOOTSTRAP, FONT_AWESOME], use_pages=True
) 
navbar = dbc.NavbarSimple(
    dbc.DropdownMenu(
        [
            dbc.DropdownMenuItem(page["name"], href=page["path"])
            for page in dash.page_registry.values()
            if page["module"] != "pages.not_found_404"
        ],
        nav=True,
        label="More Pages",
    ),
    brand="Multi Page App Plugin Demo",
    color="primary",
    dark=True,
    className="mb-3",
)
app.layout = dbc.Container(html.Div([
    navbar, dash.page_container,
    html.Div([html.Div(id="output1"), html.Div(id="output2"), dcc.Interval(id="trigger")]),
    dcc.Store(id="store-dropdown-value", data=None)    
]), fluid=True)

@app.callback(
    Output("output1", "children"), 
    Input(component_id= "trigger", component_property="n_intervals"), #### 
  
    blocking=True,
    prevent_initial_call=True
)

def TEST1(n_intervals):
        time.sleep(2) # emulate slow database
        return f"Test1 n_intervals is {n_intervals}"

if __name__ == " __main__": 
    app.run_server(debug=True, port=8003) 

```

**Page1.py**

```auto
import time, dash
import dash_bootstrap_components as dbc
from dash import callback
from dash_extensions.enrich import html, Output, Input

dash.register_page( __name__ )

layout = dbc.Container([ 
    html.Div([
    html.H2(children= "Page1",
    style={"text-align": "center", "font-size":"100%", "color":"black"})
    ]),
    html.Hr(),
    # html.Div([html.Div(id="output")]), # default interval is 1s

]) #### End Layouts

@callback(
    Output("output2", "children"), 
    Input(component_id= "trigger", component_property="n_intervals"), #### 
    blocking=True, prevent_initial_call=True
)

def TEST2(n_intervals):
        time.sleep(2) # emulate slow database
        return f"Test2 n_intervals is {n_intervals}"

```

---

<div class="post-metadata">

**Author:** ![Emil](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/emil/32/31734_2.png) [@Emil](https://community.plotly.com/u/Emil)\
**Post date:** [August 11, 2024, 4:38pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/5 "2024-08-11T16:38:44Z")

</div>

It looks like you imported the callback decorator from the wrong package (i.e. dash instead of dash-extensions).

---

<div class="post-metadata">

**Author:** ![MarinaZaitseva](https://avatars.discourse-cdn.com/v4/letter/m/85e7bf/32.png) [@MarinaZaitseva](https://community.plotly.com/u/MarinaZaitseva)\
**Post date:** [August 11, 2024, 8:20pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/6 "2024-08-11T20:20:14Z")

</div>

Thank you very much for Your Help!! You’re right.  
Now it’s working OK!

 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/0/d/0dd7ae829b70d1450fd9818851743e63dc800939.png)  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/1/8/189d0c15f92b0e8dc37f3e0573b752fc6b733c35.png)

---

<div class="post-metadata">

**Author:** ![MarinaZaitseva](https://avatars.discourse-cdn.com/v4/letter/m/85e7bf/32.png) [@MarinaZaitseva](https://community.plotly.com/u/MarinaZaitseva)\
**Post date:** [August 23, 2024, 1:51pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/7 "2024-08-23T13:51:35Z")

</div>

Emil! Help please with other problem!

 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/f/4/f45f593a47876ab2dc23552ebc4201166d4c781f.png)

I added to Page1.py a new component - dcc.RadioItems, and can’t use it correctly in the mode "blocking=True " . I tested several different components, adding it to “layout = dbc.Container” in Page1.py, and always got an error.  
1st variant without - “blocking=True” is OK

 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/2/0/2024b04c86544676460ecc32cbf5a452cf015779.png)

2nd variant with “blocking=True” give me error:

 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/a/0/a06d6bedc44eb40b58d0abac5522c6d71741ec6e.png)

If i move dcc.RadioItems from Page1.py to app.py, it’s OK again:  
 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/3/5/35d61abf681afdd32efe7986960e9fa3e046eacf.png)

 ![image](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/7/b/7b353c1f47c9df4e3a4f1a3f4d386db8f4592233.png)

As I understand, problem is with Components from pages, other than app.py.

Could you recommend me, how can I make Components in layout of Page1.py working right with a mode “blocking=True” ?

Thank You!

---

<div class="post-metadata">

**Author:** ![MarinaZaitseva](https://avatars.discourse-cdn.com/v4/letter/m/85e7bf/32.png) [@MarinaZaitseva](https://community.plotly.com/u/MarinaZaitseva)\
**Post date:** [August 23, 2024, 1:57pm UTC](https://community.plotly.com/t/blockingcallbacktransform/60752/8 "2024-08-23T13:57:22Z")

</div>

**app.py**

```auto
import time, dash 
from dash_extensions.enrich import DashProxy, callback, dcc, html, Output, Input, BlockingCallbackTransform
import dash_bootstrap_components as dbc # pip install dash-bootstrap-components

FONT_AWESOME = ("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css")
app = DashProxy(
    __name__ , suppress_callback_exceptions=True, 
    transforms=[BlockingCallbackTransform(timeout=10)],
    external_stylesheets=[dbc.themes.BOOTSTRAP, FONT_AWESOME], use_pages=True
) 
navbar = dbc.NavbarSimple(
    dbc.DropdownMenu(
        [
            dbc.DropdownMenuItem(page["name"], href=page["path"])
            for page in dash.page_registry.values()
            if page["module"] != "pages.not_found_404"
        ],
        nav=True,
        label="More Pages",
    ),
    brand="Multi Page App Plugin Demo",
    color="primary",
    dark=True,
    className="mb-3",
)
app.layout = dbc.Container(html.Div([
    navbar, dash.page_container,
    html.Div([
        html.Div(id="output1"), html.Div(id="output2"), dcc.Interval(id="trigger"),
            # dcc.RadioItems(id="radio", options = ['On', 'Off'], value = 'Off'), 
        ]),
    dcc.Store(id="store-dropdown-value", data=None)    
]), fluid=True)

@callback(
# @app.callback(            
    Output("output1", "children"),  
    Input(component_id= "trigger", component_property="n_intervals"), #### 
  
    blocking=True,
    prevent_initial_call=True
)

def TEST1(n_intervals):
        # time.sleep(2) # emulate slow database
        return f"Test1 n_intervals is {n_intervals}"

if __name__ == " __main__": 
    app.run_server(debug=True, port=8003) 

```

**Page1.py**

```auto
import time, dash
import dash_bootstrap_components as dbc
from dash_extensions.enrich import dcc, html, Output, Input, callback

dash.register_page( __name__ )

layout = dbc.Container([ 
    html.Div([
    html.H2(children= "Page1",
    style={"text-align": "center", "font-size":"100%", "color":"black"})
    ]),
    html.Hr(),
    dcc.RadioItems(id="radio", options = ['On', 'Off'], value = 'Off'), 
]) #### End Layouts

@callback(
    Output(component_id= "output2", component_property="children"), 
    Input(component_id= "radio", component_property="value"), #### 
    Input(component_id= "trigger", component_property="n_intervals"), #### 
    blocking=True,  
    prevent_initial_call=True
)

def TEST2(radio, n_intervals):
        # time.sleep(2) # emulate slow database
        return f"Test2 n_intervals is {n_intervals} radio= {radio}"

```
