Python – Flask-Bokeh-Gunicorn : Models must be owned by a single document

Flask-Bokeh-Gunicorn : Models must be owned by a single document… here is a solution to the problem.

Flask-Bokeh-Gunicorn : Models must be owned by a single document

This is a piece of code to run the Flask application and the code inspired by the Bokeh server
flask_gunicorn_embed.py on Github .

At first it felt like a charm; However, after refreshing the page, this error occurs.

Models must be owned by only a single document: … (rest truncated)

By the way, the code is run using gunicorn.
In addition, the create_figure() function returns a layout

from Decision_Tree.Plot.decision_tree import create_figure
if __name__ == '__main__':
    import sys
    sys.exit()

app = Flask(__name__)

def modify_doc(doc):
    # Create the plot
    plot = create_figure()
    # Embed plot into HTML via Flask Render
    doc.add_root(plot)

bkapp = Application(FunctionHandler(modify_doc))

# This is so that if this app is run using something like "gunicorn -w 4" then
# each process will listen on its own port
sockets, port = bind_sockets("x.x.x.x", 0)

@app.route('/', methods=['GET'])
def bkapp_page():
    script = server_document('http://x.x.x.x:%d/bkapp' % port)
    return render_template("index.html", script=script, template="Flask")

def bk_worker():
    asyncio.set_event_loop(asyncio.new_event_loop())

bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["x.x.x.x:5000"])
    bokeh_http = HTTPServer(bokeh_tornado)
    bokeh_http.add_sockets(sockets)

server = BaseServer(IOLoop.current(), bokeh_tornado, bokeh_http)
    server.start()
    server.io_loop.start()

from threading import Thread
Thread(target=bk_worker).start()

Looking forward to any help!
P.S. intentionally replace the domain with x.x.x.x.

Solution

You didn’t include all the code, so you can’t be sure, but the most likely explanation is that you’re creating Bokeh models somewhere and reusing them between different calls to modify_doc. This can occur, for example, if your create_figure function references a global ColumnDataSource (or other) that is created globally as a module outside the function. This doesn’t work, and Bokeh models can’t be reused across different documents/sessions. Each call to modify_doc needs to return a whole new set of Bokeh models for session, otherwise different users will share state, which is not good for a number of reasons (so it is explicitly forbidden by throwing that exception).

Related Problems and Solutions