Server won't launch on deployment with pn.serve

I’ve been trying out a few iterations of deploying a multi-page application into production, referring to this post here as guidance. The end of my app.py looks like this:

pn.serve({
        "":page1,
        "last_page":page3,
        "content":page2,
    },
    static_dirs={
        'assets': './static/assets',
        'thumbnails':'./static/assets/thumbnails'
        },
    port=5506,
    websocket_origin='*',
    address='IPADDRESS',
    show=False
)

where page1,page2,page3 are functions that return template.servable() objects when called. Previously I was making the mistake of launching this with panel serve app.py and this would launch the server but not render. Now I am launching with python app.py as per the recommended way of doing things, but now the server won’t even launch, it just gets stuck on Launching server at http://IPADDRESS:5506 without ever launching. Does anyone know what may be the cause of this?

Upon further investigation, it seems that although the function get_server() called by pn.serve() prints out Launching server at http://IPADDRESS:5506, it fails to return the server object, which only returns AFTER I force stop the server using CTRL-C.

After running pdb and debugging, I found the issue to be with Bokeh’s server, namely, once line 1322 in server.py is called: server.io_loop.start(), the terminal does not continue further until I kill it (somewhat unexpected). A bit of a dive down this rabbit hole shows that a Bokeh server is being spinned up, and looking in there you find actually it’s a Tornado IO Loop which is being started. Looking at Tornado’s page on HTTP servers it seems that they have been deprecating some features in Python 3.10 in regards to the way io_loops are started.

Now, I am curious whether this means that we cannot successfully start Panel apps using python app.py and simply having pn.serve() called in the file itself, or whether something else may be at issue here?

Hi @robml

I don’t understand the question as the simple example below works for me :slight_smile: Could you provide a minimum, reproducible example of what does not work for you? And explain more clearly what does not work for you. :+1:

Works for me

import panel as pn
import sys

pn.extension()

def home():
    return f"Hello Home.\n\nRunning on {sys.version}"

def page1():
    return "Hello Page 1"

def page2():
    return "Hello Page 2"

pn.serve({
    "/": home, "page1": page1, "page2": page2
})
python script.py

Please note that Python will stop at the line containing pn.serve and run until you stop the server with CTRL+C. If you want to do other things after that line you can set threaded=True, i.e. pn.serve(..., threaded=True). This will run the server in a separate thread.

Hey @Marc I think the issue I am having is somehow related to my server setup because even trying to replicate your toy example I again only got the message Launching server at ... and nothing afterwards. Whenever I tried to connect via the web browser I would get a Timeout error, although running the script via pdb it clearly showed that the server was indeed running which was very strange.

I refactored your toy example to separate apps such that home.py would look like this:

import panel as pn
import sys

pn.extension()

def home():
    return pn.pane.HTML( f"Hello Home.\n\nRunning on {sys.version}").servable()

home()

and then proceeded to launch it with panel serve home.py --address ... --allowed-websocket-origin ... along with page1 and page2 as well and THIS worked surprisingly. The output on the server is also different, showing that a Bokeh app is running at... along with messages whenever a websocket is opened or closed.

I went through the source code on Github a bit but was confused, is there a fundamental difference in function calls depending on if we use panel serve via CLI as opposed to panel.serve programmatically?

I can indeed refactor my entire codebase to be separate applications but what are some areas I should check out to see why running with python app.py via the browser inevitably? Additionally one of the reasons I opted for the programmatic approach is because I don’t need an index page instead the default page being home.py for example, which can be set as you have done but I have found no straightforward way to do so via CLI. Any help here is appreciated.