Show and Tell - Server Side Caching

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

Hi @Emil,

In the documentation of ServerSideOutputTransform, you mentioned that

it is recommended to perform scheduled cleanups outside business hours

How can cleanups be scheduled? Will restarting the app cleanup the cache?

Thanks for your help!

The cleanup can be scheduled using you method of choice. It could be a cron job, and scheduled background task in Python, a task scheduled by Windows scheduler. The best choice depends on you infrastructure setup.

Sorry, can I clarify what does a cleanup entail? Deleting the files cached in the file system? How would something like that work when deployed to something like Heroku? I apologize for these questions as I’m pretty new to the idea of caching. Thanks!

If you are using a file system store, then yes it would be deleting files. On Heroku, the file system is ephemeral, so I am not sure if manual cleaning is needed at all.

Hello everyone, i’m starting in dash and i fin usefull this dcc store concept, but i’m not pretty sure how to use in my code… now i set this compenent in a div into the layout and the first callback (the tradicional callback) set and save the data here so like 10 callbacks (taditional callbacks) take the data and process this information in order to make graphs etc… but reading this article i guess that here i can find a better way in order to make faster the app execution… @Emil can you share a code, like at the beggining, explaining the method? i couldn’t find it in your git hub repo.

Thanks in advance

Yes, you can find documentation here,

1 Like

I am getting error “AttributeError: ‘Output’ object has no attribute ‘backend’”, i have used following syntax.What could be the reason

@callback(
    ServersideOutput("store-data", "data"), 
    ServersideOutput("store-data2", "data"),
    ServersideOutput("store-data3", "data", arg_check=False, session_check=False),
    Output("data_refresh", "children"),
    Output("container","children"),
    Output("client-id-store","data"),
    Input("refresh_button","n_clicks"),
    State("url","search"),
    State("client-id-store","data"),
    State("store-data", "data"),
    State("store-data2", "data"),
    State("store-data3", "data")
    , memoize=True)

Are there any gotchas for working with multi-page apps on Heroku?

Everything is working fine locally, but the

Input("DF_GLOBAL2", "data"),

on my Heroku instance returns None. I’ve got a folder, file_system_store, on my app, and, again, it works fine locally. I’m printing when I save it initially, and the dataframe prints correctly on the server;

@app.callback(ServersideOutput("DF_GLOBAL2", "data"), Input("dummy", "children"))
def run_first(inp):
    print("Saving DF Global")
    print(DF_GLOBAL)
    return DF_GLOBAL

But when I load it above, I end up getting None objects.

Are you using more than a single pod? And/or are you restarting often? I assume you are using a disk backend?

It’s on gunicorn, 4 workers, and I’m just using the default file store. I hope that answers all the questions. Sorry I’m very weak on server side details

The instantiation of saving just looks like this:

@app.callback(ServersideOutput("global_df", "data"), Input("dummy", "children"))
def run_first(inp):
    print("Saving DF Global")
    print(DF_GLOBAL)
    return DF_GLOBAL

Any other thoughts on this?

There are a few possible issues. It looks like you might be using global variables? That can generally be a problem, so I would recommend to avoid it. Furthermore, disk caching on heroku can be problematic as the filesystem is local to the dyno (and ephemeral). If you only have a single dyno, the latter shouldn’t be an issue though.

A post was split to a new topic: Dash-extensions, ServerSideOutput error