3
votes

I was able to embed a bokeh server graph in Flask. This is the output on localhost:

enter image description here

Problem is I am not being able to make this work on Heroku. All I get displayed is the text "Here is your great site".

So, the app is made of three files.

There's the script containing the graph:

#bokeh_plot.py
import pandas as pd

from bokeh.layouts import row, widgetbox
from bokeh.models import Select
from bokeh.palettes import Spectral5
from bokeh.plotting import curdoc, figure
from bokeh.sampledata.autompg import autompg

df = autompg.copy()

SIZES = list(range(6, 22, 3))
COLORS = Spectral5
ORIGINS = ['North America', 'Europe', 'Asia']

# data cleanup
df.cyl = [str(x) for x in df.cyl]
df.origin = [ORIGINS[x-1] for x in df.origin]

df['year'] = [str(x) for x in df.yr]
del df['yr']

df['mfr'] = [x.split()[0] for x in df.name]
df.loc[df.mfr=='chevy', 'mfr'] = 'chevrolet'
df.loc[df.mfr=='chevroelt', 'mfr'] = 'chevrolet'
df.loc[df.mfr=='maxda', 'mfr'] = 'mazda'
df.loc[df.mfr=='mercedes-benz', 'mfr'] = 'mercedes'
df.loc[df.mfr=='toyouta', 'mfr'] = 'toyota'
df.loc[df.mfr=='vokswagen', 'mfr'] = 'volkswagen'
df.loc[df.mfr=='vw', 'mfr'] = 'volkswagen'
del df['name']

columns = sorted(df.columns)
discrete = [x for x in columns if df[x].dtype == object]
continuous = [x for x in columns if x not in discrete]
quantileable = [x for x in continuous if len(df[x].unique()) > 20]


def create_figure():
    xs = df[x.value].values
    ys = df[y.value].values
    x_title = x.value.title()
    y_title = y.value.title()

    kw = dict()
    if x.value in discrete:
        kw['x_range'] = sorted(set(xs))
    if y.value in discrete:
        kw['y_range'] = sorted(set(ys))
    kw['title'] = "%s vs %s" % (x_title, y_title)

    p = figure(plot_height=600, plot_width=800, tools='pan,box_zoom,reset', **kw)
    p.xaxis.axis_label = x_title
    p.yaxis.axis_label = y_title

    if x.value in discrete:
        p.xaxis.major_label_orientation = pd.np.pi / 4

    sz = 9
    if size.value != 'None':
        groups = pd.qcut(df[size.value].values, len(SIZES))
        sz = [SIZES[xx] for xx in groups.codes]

    c = "#31AADE"
    if color.value != 'None':
        groups = pd.qcut(df[color.value].values, len(COLORS))
        c = [COLORS[xx] for xx in groups.codes]
    p.circle(x=xs, y=ys, color=c, size=sz, line_color="white", alpha=0.6, hover_color='white', hover_alpha=0.5)

    return p


def update(attr, old, new):
    layout.children[1] = create_figure()


x = Select(title='X-Axis', value='mpg', options=columns)
x.on_change('value', update)

y = Select(title='Y-Axis', value='hp', options=columns)
y.on_change('value', update)

size = Select(title='Size', value='None', options=['None'] + quantileable)
size.on_change('value', update)

color = Select(title='Color', value='None', options=['None'] + quantileable)
color.on_change('value', update)

controls = widgetbox([x, y, color, size], width=200)
layout = row(controls, create_figure())

curdoc().add_root(layout)
curdoc().title = "Crossfilter"

The Flask script:

#app.py
import subprocess
import atexit
from flask import render_template, render_template_string, Flask
from bokeh.embed import autoload_server
from bokeh.client import pull_session

app = Flask(__name__)

bokeh_process = subprocess.Popen(
    ['bokeh', 'serve','--allow-websocket-origin=localhost:5000','bokeh_plot.py'], stdout=subprocess.PIPE)

@atexit.register
def kill_server():
    bokeh_process.kill()

@app.route("/")
def index():
    session=pull_session(app_path="/bokeh_plot")
    bokeh_script=autoload_server(None,app_path="/bokeh_plot",session_id=session.id)
    return render_template("index.html", bokeh_script=bokeh_script)

if __name__ == "__main__":
    print("STARTED")
    app.run(debug=True)

And the index.html template:

<!DOCTYPE html>
<html lang="en">
    <head>
        <style>
            @import url(https://fonts.googleapis.com/css?family=Noto+Sans);
            body {
              font-family: 'Noto Sans', sans-serif;
              -webkit-font-smoothing: antialiased;
              text-rendering: optimizeLegibility;
              color: #fff;
              background: #2F2F2F;
             }
        </style>
        <meta charset="utf-8">
        <title>Bokeh Crossfilter Example</title>
    </head>
    <body>
      <p> This is your great site<p>
      <div class="bk-root">
        {{ bokeh_script|safe }}
      </div>
    </body>
</html>

And this is what I get from the heroku logs. Note there's an Cannot start Bokeh server, port 5006 is already in use" line there.

heroku[web.1]: State changed from down to starting
heroku[web.1]: Unidling
heroku[web.1]: Starting process with command `gunicorn app:app`
app[web.1]: [2016-07-25 09:32:40 +0000] [3] [INFO] Starting gunicorn 19.6.0
app[web.1]: [2016-07-25 09:32:40 +0000] [3] [INFO] Listening at: http://0.0.0.0:48905 (3)
app[web.1]: [2016-07-25 09:32:40 +0000] [3] [INFO] Using worker: sync
app[web.1]: [2016-07-25 09:32:40 +0000] [7] [INFO] Booting worker with pid: 7
app[web.1]: [2016-07-25 09:32:40 +0000] [8] [INFO] Booting worker with pid: 8
heroku[web.1]: State changed from starting to up
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1641, in full_dispatch_request"
app[web.1]: Traceback (most recent call last):
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1988, in wsgi_app"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1544, in handle_user_exception"
app[web.1]:     rv = self.handle_user_exception(e)
"app[web.1]: [2016-07-25 09:32:44,050] ERROR in app: Exception on / [GET]"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/_compat.py"", line 33, in reraise"
app[web.1]:     response = self.full_dispatch_request()
"app[web.1]:     reraise(exc_type, exc_value, tb)"
app[web.1]:     raise value
"app[web.1]: OSError: Cannot pull session document because we failed to connect to the server (to start the server, try the 'bokeh serve' command)"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1639, in full_dispatch_request"
app[web.1]:     rv = self.dispatch_request()
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1625, in dispatch_request"
app[web.1]:     return self.view_functions[rule.endpoint](**req.view_args)
"app[web.1]:   File ""/app/app.py"", line 37, in index"
"app[web.1]:     session=pull_session(app_path=""/bokeh_plot"")"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/bokeh/client/session.py"", line 112, in pull_session"
app[web.1]:     session.pull()
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/bokeh/client/session.py"", line 231, in pull"
app[web.1]:     rv = self.handle_user_exception(e)
"app[web.1]:     raise IOError(""Cannot pull session document because we failed to connect to the server (to start the server, try the 'bokeh serve' command)"")"
app[web.1]: ERROR:app:Exception on / [GET]
app[web.1]: Traceback (most recent call last):
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1988, in wsgi_app"
app[web.1]:     response = self.full_dispatch_request()
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1641, in full_dispatch_request"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/_compat.py"", line 33, in reraise"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1625, in dispatch_request"
app[web.1]:     raise value
app[web.1]:     rv = self.dispatch_request()
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1639, in full_dispatch_request"
app[web.1]:     return self.view_functions[rule.endpoint](**req.view_args)
"app[web.1]:   File ""/app/app.py"", line 37, in index"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/flask/app.py"", line 1544, in handle_user_exception"
"app[web.1]:     reraise(exc_type, exc_value, tb)"
"app[web.1]:     session=pull_session(app_path=""/bokeh_plot"")"
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/bokeh/client/session.py"", line 112, in pull_session"
app[web.1]:     session.pull()
"app[web.1]:   File ""/app/.heroku/python/lib/python3.5/site-packages/bokeh/client/session.py"", line 231, in pull"
"app[web.1]:     raise IOError(""Cannot pull session document because we failed to connect to the server (to start the server, try the 'bokeh serve' command)"")"
"app[web.1]: OSError: Cannot pull session document because we failed to connect to the server (to start the server, try the 'bokeh serve' command)"
"heroku[router]: at=info method=GET path=""/"" host=bokehapp.herokuapp.com request_id=f60be826-3fba-4eab-b18f-aa0eb822ebdd fwd=""217.73.139.64"" dyno=web.1 connect=2ms service=77ms status=500 bytes=456"
"app[web.1]: 2016-07-25 09:32:44,637 Starting Bokeh server on port 5006 with applications at paths ['/bokeh_plot']"
**"app[web.1]: 2016-07-25 09:32:44,683 Cannot start Bokeh server, port 5006 is already in use"**
"app[web.1]: 2016-07-25 09:32:44,681 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 09:32:44,637 Starting Bokeh server with process id: 26"
"app[web.1]: 2016-07-25 09:32:44,620 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 09:32:55,074 WebSocket connection opened"
"app[web.1]: 2016-07-25 09:32:55,187 ServerConnection created"
"heroku[router]: at=info method=GET path=""/"" host=bokehapp.herokuapp.com request_id=41493fd5-aed9-4198-b063-652f93cee49e fwd=""217.73.139.64"" dyno=web.1 connect=0ms service=550ms status=200 bytes=1066"

I have desperately searched for an answer on the web, but haven't found anything on how to deploy a flask app that contains a bokeh server app inside. So, this post could be a good resource if anyone is able to provide an answer.

I believe the key is in the subprocess line in the app.py file where the bokeh server is called, but my knowledge in web services is limited so, can't figure out how to make it work. Any idea?

Edit 1: bigreddot suggested to change the value of --allow-websocket-origin to the url of the app. So, I did change localhost:5000 to bokehapp.herokuapp.com. That seems to fix the IOError: Cannot put session document. However, the graph still doesn't show. Here are the new logs I get from Heroku:

heroku[slug-compiler]: Slug compilation finished
heroku[slug-compiler]: Slug compilation started
heroku[web.1]: State changed from down to starting
heroku[web.1]: Starting process with command `gunicorn app:app`
app[web.1]: [2016-07-25 15:02:50 +0000] [3] [INFO] Using worker: sync
app[web.1]: [2016-07-25 15:02:50 +0000] [7] [INFO] Booting worker with pid: 7
app[web.1]: [2016-07-25 15:02:50 +0000] [3] [INFO] Starting gunicorn 19.6.0
app[web.1]: [2016-07-25 15:02:50 +0000] [3] [INFO] Listening at: http://0.0.0.0:23620 (3)
app[web.1]: [2016-07-25 15:02:50 +0000] [8] [INFO] Booting worker with pid: 8
heroku[api]: Release v7 created by [email protected]
heroku[api]: Deploy be12fcc by [email protected]
heroku[web.1]: State changed from starting to up
"app[web.1]: 2016-07-25 15:02:55,278 Starting Bokeh server with process id: 25"
"app[web.1]: 2016-07-25 15:02:55,261 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 15:02:55,276 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 15:02:55,284 Cannot start Bokeh server, port 5006 is already in use"
"app[web.1]: 2016-07-25 15:02:55,278 Starting Bokeh server on port 5006 with applications at paths ['/bokeh_plot']"
"app[web.1]: 2016-07-25 15:03:14,375 WebSocket connection opened"
"app[web.1]: 2016-07-25 15:03:15,029 ServerConnection created"
"heroku[router]: at=info method=GET path=""/"" host=bokehapp.herokuapp.com request_id=5e7a06ad-4526-4304-b00e-0c37979ab751 fwd=""109.236.33.234"" dyno=web.1 connect=1ms service=3778ms status=200 bytes=1066"
"app[web.1]: 2016-07-25 15:03:59,253 ServerConnection created"
"app[web.1]: 2016-07-25 15:03:59,133 WebSocket connection opened"

Edit 2: Some even more logs after passing --log-level=debug to subprocess:

heroku[slug-compiler]: Slug compilation started
heroku[slug-compiler]: Slug compilation finished
heroku[api]: Deploy 9c2fefa by [email protected]
heroku[api]: Release v12 created by [email protected]
heroku[web.1]: Restarting
heroku[web.1]: State changed from up to starting
heroku[web.1]: Stopping all processes with SIGTERM
app[web.1]: [2016-07-25 21:53:37 +0000] [3] [INFO] Handling signal: term
app[web.1]: [2016-07-25 21:53:37 +0000] [7] [INFO] Worker exiting (pid: 7)
app[web.1]: [2016-07-25 21:53:38 +0000] [3] [INFO] Shutting down: Master
app[web.1]: [2016-07-25 21:53:37 +0000] [8] [INFO] Worker exiting (pid: 8)
heroku[web.1]: Process exited with status 0
heroku[web.1]: Starting process with command `gunicorn app:app`
app[web.1]: [2016-07-25 21:53:53 +0000] [3] [INFO] Starting gunicorn 19.6.0
app[web.1]: [2016-07-25 21:53:53 +0000] [3] [INFO] Using worker: sync
app[web.1]: [2016-07-25 21:53:53 +0000] [8] [INFO] Booting worker with pid: 8
app[web.1]: [2016-07-25 21:53:53 +0000] [7] [INFO] Booting worker with pid: 7
app[web.1]: [2016-07-25 21:53:53 +0000] [3] [INFO] Listening at: http://0.0.0.0:41934 (3)
heroku[web.1]: State changed from starting to up
"app[web.1]: 2016-07-25 21:53:58,821 Allowed Host headers: ['localhost:5006']"
"app[web.1]: 2016-07-25 21:53:58,821 These host origins can connect to the websocket: ['bokehapp.herokuapp.com:80', 'localhost:5006']"
"app[web.1]: 2016-07-25 21:53:58,821 Patterns are:"
"app[web.1]: 2016-07-25 21:53:58,821 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 21:53:58,823     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f7bf7dd51d0>,"
"app[web.1]: 2016-07-25 21:53:58,832     <class 'bokeh.server.views.ws.WSHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,832    ('/bokeh_plot/autoload.js',"
"app[web.1]: 2016-07-25 21:53:58,831    ('/bokeh_plot/ws',"
"app[web.1]: 2016-07-25 21:53:58,832     <class 'bokeh.server.views.autoload_js_handler.AutoloadJsHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,832     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f7bf7dd51d0>,"
"app[web.1]: 2016-07-25 21:53:58,832      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,833     {'applications': {'/bokeh_plot': <bokeh.server.application_context.ApplicationContext object at 0x7f7bf7dd51d0>},"
"app[web.1]: 2016-07-25 21:53:58,823   [('/bokeh_plot/?',"
"app[web.1]: 2016-07-25 21:53:58,823     <class 'bokeh.server.views.doc_handler.DocHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,823      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,832     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f7bf7dd51d0>,"
"app[web.1]: 2016-07-25 21:53:58,833      'prefix': '',"
"app[web.1]: 2016-07-25 21:53:58,833      'use_redirect': True}),"
"app[web.1]: 2016-07-25 21:53:58,833    ('/static/(.*)',"
"app[web.1]: 2016-07-25 21:53:58,833     <class 'bokeh.server.views.static_handler.StaticHandler'>)]"
"app[web.1]: 2016-07-25 21:53:58,832      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,861 Starting Bokeh server on port 5006 with applications at paths ['/bokeh_plot']"
"app[web.1]: 2016-07-25 21:53:58,832    ('/?',"
"app[web.1]: 2016-07-25 21:53:58,833     <class 'bokeh.server.views.root_handler.RootHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,896 These host origins can connect to the websocket: ['bokehapp.herokuapp.com:80', 'localhost:5006']"
"app[web.1]: 2016-07-25 21:53:58,898   [('/bokeh_plot/?',"
"app[web.1]: 2016-07-25 21:53:58,899     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f8a84cb4b70>,"
"app[web.1]: 2016-07-25 21:53:58,896 Starting Bokeh server version 0.12.0"
"app[web.1]: 2016-07-25 21:53:58,897 Patterns are:"
"app[web.1]: 2016-07-25 21:53:58,899     <class 'bokeh.server.views.doc_handler.DocHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,896 Allowed Host headers: ['localhost:5006']"
"app[web.1]: 2016-07-25 21:53:58,900     <class 'bokeh.server.views.autoload_js_handler.AutoloadJsHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,899    ('/bokeh_plot/ws',"
"app[web.1]: 2016-07-25 21:53:58,899     <class 'bokeh.server.views.ws.WSHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,899      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,899     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f8a84cb4b70>,"
"app[web.1]: 2016-07-25 21:53:58,900      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,900    ('/bokeh_plot/autoload.js',"
"app[web.1]: 2016-07-25 21:53:58,861 Starting Bokeh server with process id: 25"
"app[web.1]: 2016-07-25 21:53:58,900     {'application_context': <bokeh.server.application_context.ApplicationContext object at 0x7f8a84cb4b70>,"
"app[web.1]: 2016-07-25 21:53:58,900      'bokeh_websocket_path': '/bokeh_plot/ws'}),"
"app[web.1]: 2016-07-25 21:53:58,901      'use_redirect': True}),"
"app[web.1]: 2016-07-25 21:53:58,900    ('/?',"
"app[web.1]: 2016-07-25 21:53:58,901    ('/static/(.*)',"
"app[web.1]: 2016-07-25 21:53:58,901     <class 'bokeh.server.views.static_handler.StaticHandler'>)]"
"app[web.1]: 2016-07-25 21:53:58,904 Cannot start Bokeh server, port 5006 is already in use"
"app[web.1]: 2016-07-25 21:53:58,900     <class 'bokeh.server.views.root_handler.RootHandler'>,"
"app[web.1]: 2016-07-25 21:53:58,901     {'applications': {'/bokeh_plot': <bokeh.server.application_context.ApplicationContext object at 0x7f8a84cb4b70>},"
"app[web.1]: 2016-07-25 21:53:58,901      'prefix': '',"
"app[web.1]: 2016-07-25 21:54:13,880 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:54:13,880 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:54:43,870 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:54:43,869 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:54:58,870 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:54:58,869 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:55:13,862 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:55:13,862 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:55:28,864 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:55:28,863 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:55:43,864 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:55:43,865 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:55:58,862 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:55:58,862 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:56:13,876 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:56:13,877 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:56:28,864 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:56:28,865 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:56:43,875 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:56:43,876 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:56:58,872 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:56:58,872 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:57:13,863 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:57:13,862 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:57:28,872 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:57:28,872 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:57:43,868 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:57:43,867 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:57:58,863 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:57:58,864 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:58:13,879 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:58:13,880 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:58:28,873 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:58:28,874 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:58:43,872 [pid 25]   /bokeh_plot has 0 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:58:43,871 [pid 25] 0 clients connected"
"app[web.1]: 2016-07-25 21:58:49,718 WebSocket connection opened"
"app[web.1]: 2016-07-25 21:58:50,223 Sending pull-doc-reply from session 'Q4LGpWidke5G85sboBiRPMazzPfwOwTDMirNrDsTY3OL'"
"app[web.1]: 2016-07-25 21:58:50,177 Receiver created for Protocol('1.0')"
"app[web.1]: 2016-07-25 21:58:50,178 ServerHandler created for Protocol('1.0')"
"app[web.1]: 2016-07-25 21:58:50,178 ServerConnection created"
"heroku[router]: at=info method=GET path=""/"" host=bokehapp.herokuapp.com request_id=15fc6908-1031-4d88-86cc-8048d6195a6f fwd=""109.236.47.207"" dyno=web.1 connect=1ms service=1341ms status=200 bytes=1066"
"app[web.1]: 2016-07-25 21:58:58,864 [pid 25]   /bokeh_plot has 1 sessions with 0 unused"
"app[web.1]: 2016-07-25 21:58:58,863 [pid 25] 1 clients connected"
1
Well one issue is that allow-websocket-origin tells the Bokeh server that it's OK to initiate websocket connections that originate from "somewhere else" (i.e. someone hitting the Bokeh server via an embedded webpage instead og navigating directly to the Bokeh server). No one will ever be originating from localhost so that value can't be right. It should be the public ip/hostname that people will navigate to to see your flask app page. - bigreddot
There might be other issues, it is hard to diagnose without also seeing the Bokeh server logs too. - bigreddot
@bigreddot thanks so much. I changed localhost:5000 to bokehapp.herokuapp.com which is the url for the app. That got rid of the IOError: Cannot pull session document. It also got rid of the internal server error which I was getting I visited bokehapp.herokuapp.com. However, the graph is still not showing on the webpage. I am not sure where to see the Bokeh server logs. I am only aware of the heroku logs command. I edited the question to show the latest logs after your proposed changes. Would be great if you showed me how to diagnose this even further. - multigoodverse
Can you confirm that the subprocess is executing in the correct location. I suppose this would mean that bokeh_plot.py in the same directory that app.py is being executed. Also, there may be issues running multiple processes with gunicorn -- i think this may mean multiple subprocess calls - quasiben
@multigoodverse did you ever get this figured out? - Eric Valente

1 Answers

-1
votes

Please check this link

The author suggested using Bokeh components method to generate script that will be embedded into the .html template.

Not sure whether it still needs two web workers though, since I am trying to make my app work on Heroku too.