Restart the dash server only when the underlying DB collection is modified

I built a chart that consumes real-time data from MongoDB, right now the dash application is configured to restart every 10 seconds, it queries the database irrespective of any changes happened in it and fetches the documents, and show that up on the screen.

Is there a way to configure the dash server to restart only if an event such as( insert, remove, update) occurred on a MongoDB collection, there’s a method to watch MongoDB (db.collection.watch()), however, I’m finding hard to integrate that within my application.

Rather than restarting the server for your Dash application, have you considered using dcc.Interval instead? You could use that to trigger a callback every 10 seconds that updates the interface with any new data.

I used dcc.Interval
image
That’s what I don’t want to call every 10 seconds, it should call only if any modifications occurred in the DB (which a watch() method will inform).

Since the collection is bigger, making frequent calls wasn’t a better option IMO.

Oh, I was confused by the language “restart”.

It sounds like you should set up a quick check so the Interval callback is as quick as possible, with another thread or process running that toggles that check in a thread-safe way. Here’s a quick sketch of a way to do this:

class DbUpdateWatchVariable():
    def __init__(self):  
         self.should_update = False # watch variable
         self.lock = multiprocessing.Lock()
    def set_should_update(new_value):
        with self.lock:
            self.should_update = new_value
    def get_and_reset_should_update():
        with self.lock:
             if self.should_update:
                 self.should_update = False
                 return True
             else:
                  return False

db_update_variable = DbUpdateWatchVariable()  # this is a global variable that will affect all sessions, but one could easily create a per-session watch variable

def monitor_db_for_updates():
    # monitor the db using db.collection.watch() here....
    # if the a change has occurred, update the watch variable
    db_update_variable.set_should_update(True)

p = multiprocessing.Process(target=monitor_db_for_updates, name='Watch the DB for updates', daemon=True)
p.start()

@app.callback(Output('output-component', 'children'),
              [Input('order_states_piechart', 'n_intervals')])
def update_with_new_data(n):
    should_update = db_update_variable.get_and_reset_should_update()
    if not should_update:
        raise PreventUpdate  # no changes need to be made!
    else:
         # recompute and return any changes that need to be made to the output components

Note that even a very high update interval would be very cheap to execute in the case where no change has occurred in the DB.

1 Like

Oh, I didn’t answer one aspect of your question. “it should call only if any modifications occurred in the DB” I’m a beginner to Dash too, but to my knowledge there is currently no way to do this kind of “subscribe and notify me” callback. The only way to do dynamic updates is in response to a user action that triggers a callback or a dcc.Interval callback. If someone else knows a workaround, please let me know!