ctrl-c does not work after server.restart() is called (win32)

Christian Wyglendowski avatarChristian Wyglendowski created an issue

A call to cherrypy.server.restart() keeps the console window on win32 from accepting ctrl-c to stop the server. If your code calls cherrypy.server.stop() from within, the server will stop ok.

Comments (12)

  1. Christian Wyglendowski

    On a related note, and something that would go some ways towards solving this issue - there should be a distinction between stopping and shutting down a CherryPy application.

    Stopping should halt the app server from handling requests; essentially stopping the app server, but not ending the application.

    Shutting down should take it a step further and actually end the application.

  2. Christian Wyglendowski

    Ok, I have a patch that corrects the restart behavior on win32.

    It also goes a bit further to address my comment above and implements suspend() and resume() functions that do pretty much what you would think. If I am thinking right (don't listen to speno :-) ), this should allow a separate thread (perhaps a GUI control app or something) to suspend, resume, and stop a running CP application. Anyhow..

    The main changes that I made are:

    • A global "command" variable (valid values are 'start', 'stop', 'suspend')
    • start() now contains a loop that dispatches differently depending upon the value of command
    • When restart is called, the server is not restarted in another thread. Instead, the current server exits back to the loop in start(), where it, um _start()s again

    The names of some of the original functions now belie their functionality somewhat. I didn't bother those sorts of tedious changes at this point because I wanted to get some feedback on my method of solving this problem.

    Even though the CP test suite passes on my platform (WinXP), it would be a good idea to test it on some others. Check out the patch and the accompanying test application, and let me know what you think.

  3. Robert Brewer

    It's *possible* that this was fixed with [691], care to try it?

    Regardless, much has changed (underneath this patch) with [691] (see source:/trunk/cherrypy/server.py#691). Some notes:

    1. There's no more "finally" clause in server.run_server(); server.stop() was being called twice, but should only be called if !KeyboardInterrupt or !SystemExit is raised.

    2. You don't need to "wait for worker threads to stop" after httpstop()--HTTP servers MUST stop all worker threads before their .stop() method returns. I'll try to write this fact (and some related issues) into the book.

    3. I'm not a fan of putting a time.sleep() into server.py in order to implement suspend. Perhaps I'm misunderstanding your design, but I think the caller should instead write something like the current innards of restart():

    while waiting:

    4. The restart function currently knows what server to start via the local "http" variable; that should probably be changed into a "httpClass" global so the example in point 3 can actually work. ;)

    5. The restart function works better if it starts a new thread, because it allows a caller function to more easily call server.wait_until_ready (a new function in [691]).

    6. Plus all that stuff in the IRC note. ;)

  4. Christian Wyglendowski

    Well, still no-go with a restart. In fact, I get a traceback now:

      File "C:\Python24\Lib\site-packages\cherrypy\_cphttptools.py", line 272, in run
      File "C:\Python24\Lib\site-packages\cherrypy\_cphttptools.py", line 497, in main
        body = page_handler(*args, **cherrypy.request.paramMap)
      File "C:\Documents and Settings\Christian\Desktop\cp_playground\restart_test.py", line 8, in restart
      File "C:\Python24\Lib\site-packages\cherrypy\server.py", line 239, in restart
      File "C:\Python24\Lib\site-packages\cherrypy\server.py", line 257, in wait_until_ready
        wait_for_occupied_port(host, port)
      File "C:\Python24\Lib\site-packages\cherrypy\server.py", line 295, in wait_for_occupied_port
        raise cherrypy.NotReady("Port not bound.")
    NotReady: Port not bound. - - [2005/09/28 22:16:09] "GET /restart HTTP/1.1" 500 1480

    A few questions/observations:

    On # 3 - Do you think that a suspend command should be up to the client to create? The use of "suspend" in my mind moved towards satisfying the goal of my first comment on this ticket (being able to stop the app server without stopping the app).

    On # 5 - I think that starting the server in a new thread is close to the root of the problem. When server.restart() launches the appserver in a new thread, server.start() '''ends''', thus ending the main thread of the user's application. Run the attached littlethreadtest.py to see what I mean - try and interrupt it with a Ctrl-C. If you run restart_test.py, and visit http://localhost:8080/restart at least once, you will get the same sort of behavior.

    That is why I had a loop in start(). It at least allowed a "restart" without requiring a new thread. But I guess that introduces issues of its own...

  5. Christian Wyglendowski

    Some more observations:

    I finally got around to testing the restart functionality in Linux. The rc1 code seems to shutdown, rather than restart, when server.restart() is called from within an exposed method. The code in [691] actually restarts, and you can sent a Ctrl-C to successfully stop the server after up to 2 restarts. After that, sending a Ctrl-C hangs the process and it must be killed.

    I also realize that I might be wrong in my second comment above (regarding fumanchu's point 5). Either that, or at least my "littlethreadtest.py" doesn't represent the problem well at all.

    In any event, the plot thickens...

  6. Christian Wyglendowski

    A little closer it seems. The server '''does''' restart now, but I still get the same traceback as above (the line numbers are different, of course). Once it is restarted, a Ctrl-C still does not stop the server.

  7. Robert Brewer

    Okay, after much review, I don't think there's a way to solve this other than forcing developers to always call server.start from the main thread, and then having that main thread block indefinitely with a time.sleep() loop; the HTTP server would always have to be started in a new thread (inside run_server).

    This means that the "initOnly" arg to start() should disappear (or at least do nothing), which would be a big change to the API, and would have to be discussed in depth before implementing it in 2.1.

    Christian, the issue where restart() doesn't restart is something else: as the traceback points out, your port isn't getting rebound. I had the same problem, but oddly enough, only on localhost; once I switched to a remote client it went away...not sure why.

  8. Log in to comment
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.