You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Plotly Dash实现服务器端缓存:解决多客户端定时更新引发的数据库死锁问题

How to Update Server-Side dcc.Store with a Global Scheduled Task (Avoid Database Deadlocks from Multiple Clients)

Great question—this is a super common pain point with Dash when scaling to multiple users. The issue with your current setup is that dcc.Interval runs per client session, so every connected user triggers their own database query. That’s a surefire way to hit database deadlocks fast.

APScheduler is exactly the right tool here: it lets you run a single, server-side scheduled task that fetches data once and shares it with all clients. Here’s how to integrate it cleanly with your existing Dash app and dcc.Store:


Step 1: Install Required Packages

First, add APScheduler to your environment:

pip install apscheduler

Step 2: Modified Full Code with APScheduler Integration

Here’s the adjusted version of your app, with comments explaining key changes:

from apscheduler.schedulers.background import BackgroundScheduler
import pyodbc
import pandas as pd
from dash import Dash, html, dcc, Input, Output, Trigger
from dash_extensions.enrich import CallbackCache, FileSystemCache

app = Dash(__name__)
app.layout = html.Div([ 
    html.Button("Query data", id="btn"),
    dcc.Graph(id='Time-graph', style={'width': '100%', 'height': '900px'}), 
    dcc.Store(id="store", storage_type="session"), 
    dcc.Interval( 
        id='interval-component-Time', 
        interval=1 * 8000, # Keep your original update interval
        n_intervals=0 
    ) 
]) 

# Reuse your existing cache setup for shared data storage
cc = CallbackCache(cache=FileSystemCache(cache_dir="../cache"))
GLOBAL_DATA_KEY = "shared_database_data"  # Unique key for cached data

# 1. Define the server-side database query task
def scheduled_data_fetch():
    # Connect to DB and fetch data (same logic as before)
    channel = pyodbc.connect("...connection string...")
    Run = pd.read_sql("command ", channel).iloc[0]['Name']
    Event = pd.read_sql("command ", channel).iloc[0]['EventId']
    Lap = pd.read_sql("command ", channel)
    groups = [Run, Event, Lap]
    
    # Store results in global cache (shared across all clients)
    cc.cache.set(GLOBAL_DATA_KEY, groups)
    channel.close()  # Critical: avoid database connection leaks

# 2. Initialize and start the scheduler
scheduler = BackgroundScheduler()
# Run the fetch task every 8 seconds (matches your original interval)
scheduler.add_job(scheduled_data_fetch, 'interval', seconds=8)
scheduler.start()

# 3. Client-side callback: Pull cached data to update dcc.Store
@cc.cached_callback(Output("store", "data"), [Trigger("interval-component-Time", "n_intervals")])
def update_store_from_cache():
    # Fetch pre-computed data from cache instead of querying DB
    return cc.cache.get(GLOBAL_DATA_KEY)

# 4. Your existing graph update callback stays the same
@cc.callback(Output("Time-graph", "figure"), [Input("store", "data")])
def update_graph(data):
    if not data:
        # Handle case where initial data hasn't loaded yet
        return {}
    # ...your existing figure generation code...
    return fig

# Optional: Add manual refresh via button
@cc.callback(Output("store", "data"), [Input("btn", "n_clicks")], prevent_initial_call=True)
def manual_refresh(n_clicks):
    scheduled_data_fetch()  # Trigger immediate data update
    return cc.cache.get(GLOBAL_DATA_KEY)

cc.register(app)

if __name__ == '__main__':
    try:
        app.run_server(debug=True)
    finally:
        # Clean up scheduler when server shuts down
        scheduler.shutdown()

Key Improvements & Explanations

  • Single Source of Truth: APScheduler runs one background task on the server, so only one database query happens every 8 seconds—no matter how many clients are connected. This eliminates the deadlock issue entirely.
  • Cache Reuse: We leverage your existing FileSystemCache to store the latest database results. All clients pull from this shared cache instead of hitting the DB directly.
  • Resource Safety: Added explicit database connection closure and scheduler shutdown to prevent resource leaks.
  • Backward Compatibility: Kept your original dcc.Interval and dcc.Store setup, so client-side behavior feels identical to users.

内容的提问来源于stack exchange,提问作者MaxB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:28:17