Show and Tell - Server Side Caching

Your advice from another thread brought me here.

Very interested in trying this out. Looking at the MRE, it seems like we should replace Dash, Output, and Input imports that were originally from dash, with dash_extensions.enrich.

Just curious why this would be the arrangement, wouldn’t it have been easier to import onlyServersideOutput from dash_extensions.enrich alone, while importing the rest from the original dash library.

Additionally, when file_system_store is created as a folder, wouldn’t the data still eventually need to be transmitted from the server to the client? How are you able to achieve such speed?

1 Like

I am modifying the behavior of the objects that you mention, that is why they must be imported differently.

No, the data stays on the server. That is essentially how the performance improvement is achieved.

Okay, and in the MRE - each time the button is clicked, the data in file_system_store on the server is updated right? Perhaps I’d look to use a dcc.Interval to return the latest data into ServersideOutput, from which I can use as inputs to my charts.

Is it as simple as I’m making it out to be?

Yes, that sounds about right. That being said, for your use case it seems to me that a scheduled background task (running on the server at regular intervals) that updates a server cache might be a more proper design.

I assume you’re recommending so, so that the data can be updated even though nobody is visiting the site, and the expensive querying step will not hinder the first visitor, right?

Would I look up on flask caching sql query for more information on the separately scheduled background task?

Yes, exactly. There are tons of tools that could be used. A simple solution could be a Python script that fetches the data and writes them to a file invoked by a scheduler, e.g. Cron or a Python one.

1 Like

does ServersideOutput work with the callbacks on dash 2.0’s all-in-one components ?

I haven’t tested it, but i believe so. As I understand, they are just “normal” pattern matching callbacks. However it does not work with the new decorator that omits the app object.

Thank you for the reply. The new @callback is what I was referring to and your reply confirms my observation.

Any plan to make it work for the new @callback? or is it even possible to make it work when an dash AIO component has no knowledge of app object and in the meantime flask_caching is coupled with an app object?

I believe it should be possible, I already have a few ideas on how to address it.

ive pip installed and it did not work any idea?
ModuleNotFoundError: No module named ‘dash_extensions.enrich’

What OS, dash and dash-extensions versions are you using?

1 Like

Hello @Emil,

Still getting a lot of use out of your dash-extensions package so thanks again!

I had a question in regards to dash-labs and the latest syntax with dash-extensions. I was trying out the new /pages feature with one of my apps that utilizes dash-extensions. I was having issues getting any of my callbacks to run (both normal and serverside), and so I updated dash-extensions package and checked the latest documentation. I think it might be tied to some changes in dash-extensions’ syntax. My imports used to look like this:

from dash_extensions.enrich import ( 
    Dash,
    ServersideOutput,
    Output,
    Input,
    State,
    FileSystemStore,
)

However, referencing your repo, it looks like I should just be importing ServersideOutputTransform() and DashProxy. This resulted in two issues for me:

  1. I can no longer set the output_defaults when using DashProxy as the parameter is not recognized. Is there still a way to modify the backend and session_check parameters?
  2. Even after passing ServersideOutputTransform() to the transforms keyword argument, using ServersideOutput in my callbacks results in a NameError: name 'ServersideOutput' is not defined. I’m not sure what I’m missing here as ServersideOutput is still used in the documentation.

I’m assuming this is all tied to the fact that the documentation no longer shows the output, input, or state custom objects. Is there a new way to register the callbacks on the Dash app object? Either way, so far, I’ve had no luck getting the dash-extensions’ callbacks to run when trying to use the new /pages feature.

Thanks again for supporting this package, any help/guidance is appreciated!

@bigmike Could you post a minimal example demonstrating what is is that isn’t working? I have recently update dash-extensions to support the Dash 2 syntax, so that is expected to work. However, I haven’t played around with the pages feature of dash-labs, so I can’t say if that introduces some incompability.

I went ahead and slightly modified the /pages example to try and highlight the issue.
app.py:

from dash_extensions.enrich import ( 
    Dash,
    FileSystemStore,
)
import dash
import dash_bootstrap_components as dbc
import dash_labs as dl


# Setup file caching
fss = FileSystemStore(cache_dir="cache")
output_defaults = dict(
    backend=fss, session_check=False
)  # Turned off session check in order to share global data

# App Instance
app = Dash(
    __name__,
    plugins=[dl.plugins.pages],
    external_stylesheets=[dbc.themes.BOOTSTRAP],
    output_defaults=output_defaults,
)

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-2",
)

app.layout = dbc.Container(
    [
        navbar,
        dl.plugins.page_container,
    ],
    fluid=True,
)

if __name__ == "__main__":
    app.run_server(debug=True, host="0.0.0.0")

The home page shown below uses the dash-extensions callback and results in a 404 error. This can be fixed by commenting out from app import app and adding from dash import callback then using the @callback syntax. However, the serverside outputs will no longer work correctly once you do this. The resulting error when using a serverside output is that the object returned is not “JSON serializable” . I assume this is because dash-extensions is no longer taking care of the serialization and the callback is trying to return the entire object to the browser instead of just the key.

pages/home.py:

from dash_extensions.enrich import (
    Output,
    Input,
)
import dash

dash.register_page(__name__, path="/")
from app import app
from dash import dcc, html
import plotly.express as px

df = px.data.medals_wide(indexed=True)

layout = html.Div(
    [
        html.H1("Dash Extensions:"),
        dcc.Checklist(
            id="heatmaps-medals",
            options=[{"label": x, "value": x} for x in df.columns],
            value=df.columns.tolist(),
        ),
        dcc.Graph(id="heatmaps-graph"),
    ]
)


@app.callback(Output("heatmaps-graph", "figure"), Input("heatmaps-medals", "value"))
def filter_heatmap(cols):
    fig = px.imshow(df[cols])
    return fig

This is the standard dash syntax that works without issue.

standard.py

import dash

dash.register_page(__name__, path="/test")

from dash import dcc, html, Output, Input, callback
import plotly.express as px

df = px.data.medals_wide(indexed=True)

layout = html.Div(
    [
        html.H1("Standard Dash Library"),
        dcc.Checklist(
            id="heatmaps-medals",
            options=[{"label": x, "value": x} for x in df.columns],
            value=df.columns.tolist(),
        ),
        dcc.Graph(id="heatmaps-graph2"),
    ]
)


@callback(Output("heatmaps-graph2", "figure"), Input("heatmaps-medals", "value"))
def filter_heatmap(cols):
    return px.imshow(df[cols])

Hello all,
I have a simple question for the usage of ServersideOutput.
Is it necessary to convert all instances of Input, Output, State in an Dash app from dash.dependencies to dash_extensions.enrich to enable ServersideOutput?
I am using DashProxy object to initiate the app and using ServersideOutput in 1 out of 40 callbacks.

from dash_extensions.enrich import DashProxy, ServersideOutputTransform
app = DashProxy(
    transforms=[
        ServersideOutputTransform(backend=fss),  # enable use of ServersideOutput objects
    ],
    external_stylesheets=[dbc.themes.BOOTSTRAP],
)

I am facing some errors when deploying Dash docker to Azure App Service and eliminating all possible root causes.
Thank you!

Hey everyone,

Does anyone know if it is possible to ignore certain arguments when using memoization? It appears this should be possible as flask caching has an “args_to_ignore” parameter but I’m unsure where to include this parameter in the callback.

Thanks in advance for any help!

Hi @Emil

Thanks for the sample code a couple of years ago,

How do i install dash_extensions in pycharm. New to python and not able to figure this out but it seems that this would be greatly helpful.

Sorry, if the question is already answered. Please direct me to the answer if already answered.

You can just use pip like with other packages :slight_smile:

Hi @raaja.yoga
Welcome to the community, I hope this image will help you with the installation of dash_extensions

As you can see, I clicked on the ‘terminal’ tab at the very bottom, and then I typed that pip install text to install dash-extensions