развернуть приложение Bokeh flask на Heroku - я попробовал все возможное, но безуспешно - PullRequest
0 голосов
/ 24 января 2020

Я занимаюсь разработкой простого приложения Bokeh, встроенного в Flask, и хочу развернуть его на Heroku. Я думаю, что я рассмотрел большинство рассуждений, связанных с этой проблемой на Guithub, Stackoverflow и дискурсе боке.

Я следую этому flask_gunicorn_embed.py , чтобы встроить боке в Flask.

каждый раз, когда я запускаю его, я получаю пустую страницу в http://bokehapp.herokuapp.com/app без проблем или ошибок в консоли браузера

Я думаю, что ошибка где-то в одной из следующих 3 строк:

> sockets, port = bind_sockets("localhost", 0)
> script = server_document('https://bokehapp.herokuapp.com:%d/bkapp' % port)
> bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["bokehapp.herokuapp.com:8000", "*"])

вот мой код app.py:

try:
    import asyncio
except ImportError:
    raise RuntimeError("This example requries Python3 / asyncio")

from flask import Flask, render_template

from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.embed import server_document
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.server.server import BaseServer
from bokeh.server.tornado import BokehTornado
from bokeh.server.util import bind_sockets
from bokeh.themes import Theme

if __name__ == '__main__':
    print('This script is intended to be run with gunicorn. e.g.')
    print()
    print('    gunicorn -w 4 flask_gunicorn_embed:app')
    print()
    print('will start the app on four processes')
    import sys
    sys.exit()

from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature

app = Flask(__name__)


def modify_doc(doc):
    df = sea_surface_temperature.copy()
    source = ColumnDataSource(data=df)

    plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43")
    plot.line('time', 'temperature', source=source)

    def callback(attr, old, new):
        if new == 0:
            data = df
        else:
            data = df.rolling('{0}D'.format(new)).mean()
        source.data = ColumnDataSource(data=data).data

    slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
    slider.on_change('value', callback)

    doc.add_root(column(slider, 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("localhost", 0)


@app.route('/', methods=['GET'])
def bkapp_page():
    script = server_document('https://bokehapp.herokuapp.com:%d/bkapp' % port)
    return render_template("embed.html", script=script, template="Flask")


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

    bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["bokehapp.herokuapp.com:8000", "*"])
    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()

вот мой html код (код для вставки html):

<!doctype html>

<html lang="en">
<head>
    <link rel="stylesheet" type="text/css" href="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.css"/>
    <link rel="stylesheet" type="text/css" href="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.css"/>
    <link href="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.css" rel="stylesheet" type="text/css">
    <script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script>
    <script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
  <meta charset="utf-8">
  <title>Embedding a Bokeh Server With {{ framework }}</title>
</head>

<body>
  <div>
  {{ div | safe }}
  {{ script|safe }}
  </div>

</body>
</html>

вот логи герою:

2020-01-24T18:45:13.848829+00:00 heroku[web.1]: Starting process with command `bokeh serve --port=XXXXX --allow-websocket-origin=bokehapp.herokuapp.com --address=0.0.0.0 --use-xheaders app.py`
2020-01-24T18:45:18.188153+00:00 app[web.1]: 2020-01-24 18:45:18,187 Starting Bokeh server version 1.4.0 (running on Tornado 4.4.2)
2020-01-24T18:45:18.190044+00:00 app[web.1]: 2020-01-24 18:45:18,189 User authentication hooks NOT provided (default user enabled)
2020-01-24T18:45:18.193171+00:00 app[web.1]: 2020-01-24 18:45:18,193 Bokeh app running at: http://0.0.0.0:25630/app
2020-01-24T18:45:18.193327+00:00 app[web.1]: 2020-01-24 18:45:18,193 Starting Bokeh server with process id: 4
2020-01-24T18:45:18.797915+00:00 heroku[web.1]: State changed from starting to up
2020-01-24T18:45:23.000000+00:00 app[api]: Build succeeded
2020-01-24T18:52:25.994188+00:00 heroku[router]: at=info method=GET path="/" host=bokehapp.herokuapp.com request_id=563bd8a0-XXXX-XXXX-987e-d7289d568b49 fwd="93.178.XX.XXX" dyno=web.1 connect=0ms service=5ms status=302 bytes=163 protocol=https
2020-01-24T18:52:27.369963+00:00 heroku[router]: at=info method=GET path="/app" host=bokehapp.herokuapp.com request_id=56c8d8b1-20a6-4d50-b84d-6a8f9854598b fwd="93.178.XX.XXX" dyno=web.1 connect=0ms service=1028ms status=200 bytes=2681 protocol=https
2020-01-24T18:52:27.355029+00:00 app[web.1]: 2020-01-24 18:52:27,354 User authentication hooks NOT provided (default user enabled)
2020-01-24T18:52:27.372464+00:00 app[web.1]: Exception in thread Thread-1:
2020-01-24T18:52:27.372468+00:00 app[web.1]: Traceback (most recent call last):
2020-01-24T18:52:27.372471+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/threading.py", line 917, in _bootstrap_inner
2020-01-24T18:52:27.372474+00:00 app[web.1]: self.run()
2020-01-24T18:52:27.372477+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/threading.py", line 865, in run
2020-01-24T18:52:27.372479+00:00 app[web.1]: self._target(*self._args, **self._kwargs)
2020-01-24T18:52:27.372481+00:00 app[web.1]: File "/app/app.py", line 381, in bk_worker
2020-01-24T18:52:27.372483+00:00 app[web.1]: server.io_loop.start()
2020-01-24T18:52:27.372485+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.7/site-packages/tornado/ioloop.py", line 752, in start
2020-01-24T18:52:27.372487+00:00 app[web.1]: raise RuntimeError("IOLoop is already running")
2020-01-24T18:52:27.372489+00:00 app[web.1]: RuntimeError: IOLoop is already running
2020-01-24T18:52:27.372536+00:00 app[web.1]:
2020-01-24T18:52:31.719924+00:00 app[web.1]: 2020-01-24 18:52:31,719 WebSocket connection opened
2020-01-24T18:52:31.737203+00:00 app[web.1]: 2020-01-24 18:52:31,736 ServerConnection created

вот мои требования file:

gunicorn 
pandas 
numpy
flask
bokeh
Tornado==4.4.2

вот файл procfile:

web: bokeh serve --port=$PORT --allow-websocket-origin=bokehapp.herokuapp.com --address=0.0.0.0 --use-xheaders app.py

Я очень ценю помощь !!

Спасибо,
Зияд

...