Repository: bokeh/bokeh

Issue:
flask_gunicorn_embed.py does not work with Tornado 5
ref: https://github.com/bokeh/bokeh/blob/master/examples/howto/server_embed/flask_gunicorn_embed.py

Running as is gets:
```
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/bryanv/work/bokeh/examples/howto/server_embed/flask_gunicorn_embed.py", line 72, in bk_worker
    server.start()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/site-packages/bokeh/server/server.py", line 149, in start
    self._tornado.start()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/site-packages/bokeh/server/tornado.py", line 372, in start
    self._stats_job.start()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/site-packages/tornado/ioloop.py", line 1185, in start
    self.io_loop = IOLoop.current()
  File "/Use
rs/bryanv/anaconda/envs/01216/lib/python3.6/site-packages/tornado/ioloop.py", line 282, in current
    loop = asyncio.get_event_loop()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/asyncio/events.py", line 694, in get_event_loop
    return get_event_loop_policy().get_event_loop()
  File "/Users/bryanv/anaconda/envs/01216/lib/python3.6/asyncio/events.py", line 602, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Thread-1'.
```

Tried changing worker to 
```
def bk_worker():
    io_loop = IOLoop())
    server = BaseServer(io_loop, bokeh_tornado, bokeh_http)
    server.start()
    server.io_loop.start()
```


but then the http requests to the `HTTPServer` just hang (the workers are getting executed the right number of times though)

cc @bdarnell any quick ideas?


Discussion:
In the thread, do `asyncio.set_event_loop(asyncio.new_event_loop())`. This is necessary any time you want to use asyncio in a thread other than the main thread. (You could also use [AnyThreadEventLoopPolicy](http://www.tornadoweb.org/en/stable/asyncio.html#tornado.platform.asyncio.AnyThreadEventLoopPolicy) if you were going to have a lot of threads)
Is there not a solution that works for python 2 and 3?
No; you'll need to use a conditional import.
OK, thanks for the info!
I think I will just just make the example print a message saying it only works with python 3 actually
@bdarnell hrm I still can't get this to work. That change removed the error, but things things just hang forever when it tries to to hit the URL at the port that is bound manually:

http://localhost:54526/bkapp/autoload.js?bokeh-autoload-element=c4d9c8a4-5652-42a0-ae3f-ed8f22551d68&bokeh-app-path=/bkapp&bokeh-absolute-url=http://localhost:54526/bkapp

I might just remove this example altogether, but if you have any quick ideas, I'd love to try them. 
  
Everything that touches Tornado should be run on the thread where the IOLoop will be run, so you need to move the creation of the HTTPServer, etc, to the thread. 

Resolving patch:
diff --git a/examples/howto/server_embed/flask_gunicorn_embed.py b/examples/howto/server_embed/flask_gunicorn_embed.py
--- a/examples/howto/server_embed/flask_gunicorn_embed.py
+++ b/examples/howto/server_embed/flask_gunicorn_embed.py
@@ -1,3 +1,8 @@
+try:
+    import asyncio
+except ImportError:
+    raise RuntimeError("This example requries Python3 / asyncio")
+
 from flask import Flask, render_template
 
 from tornado.httpserver import HTTPServer
@@ -52,13 +57,9 @@ def callback(attr, old, new):
 # can't use shortcuts here, since we are passing to low level BokehTornado
 bkapp = Application(FunctionHandler(modify_doc))
 
-bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["localhost:8000"])
-bokeh_http = HTTPServer(bokeh_tornado)
-
 # 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)
-bokeh_http.add_sockets(sockets)
 
 @app.route('/', methods=['GET'])
 def bkapp_page():
@@ -66,8 +67,13 @@ def bkapp_page():
     return render_template("embed.html", script=script, template="Flask")
 
 def bk_worker():
-    io_loop = IOLoop.current()
-    server = BaseServer(io_loop, bokeh_tornado, bokeh_http)
+    asyncio.set_event_loop(asyncio.new_event_loop())
+
+    bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["localhost: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()
 


Test patch: