Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.
This repository was archived by the owner on Aug 29, 2025. It is now read-only.

Cannot run Dash in a thread in Debug mode #952

Open

Description

@e-dervieux

I would like to build an application using some kind of model-view-controller pattern with two main threads:

  • One thread running the Dash application (View)
  • Another one performing real time control of a machine through a serial link (Model & Controller)

Here is a minimal working example of a typical code to perform such a task:

import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import threading
import time

counter = 0


class DashThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run(self):
        global counter

        app = dash.Dash(__name__)

        app.layout = html.Div([
            dcc.Interval(id='my_interval', disabled=False, n_intervals=0),
            html.Div("Counter :", style={"display": "inline-block"}),
            html.Div(children=None, id="cnt_val", style={"display": "inline-block", "margin-left": "15px"}),
        ])

        @app.callback(Output('cnt_val', 'children'), [Input('my_interval', 'n_intervals')])
        def update(n_intervals):
            return counter

        app.run_server(dev_tools_silence_routes_logging=True, debug=True)


class CountingThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run(self):
        global counter

        while True:
            counter += 1
            print(counter)
            time.sleep(1)


a = DashThread("The Dash Application")
b = CountingThread("An Independent Thread")

b.start()
a.start()

a.join()
b.join()

This scripts creates two Thread objects:

  • DashThread containing a Dash application which periodically updates the display of the global variable counter.
  • CountingThread, which periodically increases the global variable counter

However, the code crashes with the error:

Traceback (most recent call last):
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/Users/XXX/OneDrive - Biosency/Python/05_a_atmos/src/test_c.py", line 31, in run
    app.run_server(dev_tools_silence_routes_logging=True, debug=True)
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/site-packages/dash/dash.py", line 1718, in run_server
    self.server.run(host=host, port=port, debug=debug, **flask_run_options)
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/site-packages/flask/app.py", line 990, in run
    run_simple(host, port, self, **options)
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/site-packages/werkzeug/serving.py", line 1050, in run_simple
    run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/site-packages/werkzeug/_reloader.py", line 330, in run_with_reloader
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
  File "/Users/XXX/anaconda3/envs/multiproc_env/lib/python3.8/signal.py", line 47, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread

This seems to be related to the fact that Flask does not like to be launched in another thread that the main one, especially with the debug=True option, as documented here and there.

I tried to adapt this answer yielding the following code:

[...]
import time

counter = 0
app = dash.Dash(__name__)


class DashThread(threading.Thread):
[...]
def run(self):
        global counter
        global app

        app.layout = html.Div([
[...]

without success. The issue disappears, however, if I remove the debug=True argument, leading:

[...]
def update(n_intervals):
            return counter

        app.run_server(dev_tools_silence_routes_logging=True)  # , debug=True) <- Commented out


class CountingThread(threading.Thread):
[...]

it works fine. Except of course, I am no longer able to use the debugging functionalities such as reload on save, etc.


Could this issue be solved by changing the way Flaskis called inside the Dash libraries?


Reproduced with Python 3.8, dash 1.20.0, flask 1.1.2.

Activity

  1. berthoud commented on Dec 29, 2023

    @berthoud

    Before finding this I asked the same question on stackexchange at https://stackoverflow.com/questions/77724451/how-to-run-a-dash-app-with-threading-and-with-debug-true maybe someone can help us there.

  2. sanskarbiswal commented on Mar 22, 2024

    @sanskarbiswal

    Try using the following

    app.run_server(debug=True, use_reloader=False)

  3. berthoud commented on Mar 23, 2024

    @berthoud

    This works - thanks Sanskarbiswal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions