Opened 10 years ago

Closed 10 years ago

#24398 closed Bug (needsinfo)

Built in webserver not reloading Python files upon requests

Reported by: Zsolt Ero Owned by: nobody
Component: Uncategorized Version: 1.7
Severity: Normal Keywords: server runserver
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Zsolt Ero)

I am experiencing the following bug in Django 1.7.4:

  1. Create a new default project
  2. Create a new default app.
  3. Make a view + url, just return a simple string in a HttpResponse.
  4. Start "manage.py runserver"
  5. Load the URL in browser / curl.
  6. Change string in the view.
  7. Reload the URL in browser / re-run curl.

What should happen:
The updated contents should be shown in the browser / curl.

What is happening:
Sometimes the updated content is displayed.
Most of the time the old content is displayed.

Note 1:
If I wait a while (say 5 minutes), and reload, the updated content will be displayed.
If I do not wait, but simply click reload-reload-reload, the old content will be displayed all the time.

Note 2:
If I hit the force-reload button in the browser (by clicking Ctrl + refresh or similar), then it triggers a server reload/restart. However the result of this response is still the old content. However if I do a normal request now (so it's the 2nd request after reload), then the updated content is displayed.

Note 3:
A very interesting, possibly related bug: if I hit Ctrl + C to quit the server and restart it, it terminates with error"

Error: That port is already in use.

To be able to restart the server I have to wait quite a while (say 20 seconds). This error seems to only happen when the server is in the "stuck" mode, as in displaying the old content.

Python version: 2.7.9, latest from homebrew
Django version: 1.7.4, latest from pip
OS version: OS X 10.9.5

Change History (15)

comment:1 by Zsolt Ero, 10 years ago

Description: modified (diff)

comment:2 by Zsolt Ero, 10 years ago

Description: modified (diff)

comment:3 by Zsolt Ero, 10 years ago

Sorry, it seems while I did an edit someone added these, but by clicking update I removed these 3 from the ticket:

Needs documentation unset
Needs tests unset
Patch needs improvement unset

comment:4 by Carl Meyer, 10 years ago

It seems like you might have some kind of orphaned or zombie runserver process running in the background and interfering with things. Can you try restarting your computer, running ps wuax | grep runserver to ensure there are no runserver processes running, then start runserver (just once) and see if you can still reproduce these issues?

in reply to:  4 comment:5 by Zsolt Ero, 10 years ago

Even before restarting the computer, there isn't any process for "ps wuax | grep runserver", except for the grep one. I'll try restarting now.

comment:6 by Carl Meyer, 10 years ago

Have you ever started any other kind of server that might be serving on the same port? Gunicorn, uWSGI, Apache...?

comment:7 by Zsolt Ero, 10 years ago

Same behaviour after restart.

  1. No change upon reloading. Finally it reloaded after 24 seconds of continuous Cmd + R.
  2. Port error after quitting the server.
  3. Had to wait 15 seconds (tested by re-running the last command every second), till it allowed actually running the server.
Last edited 10 years ago by Zsolt Ero (previous) (diff)

comment:8 by Zsolt Ero, 10 years ago

  1. No other webserver installed on the system.
  2. Zombie process confirmed, when in "stuck" state, the ps wuax displays the process in the list.
  3. After quitting the server and back in terminal, the following warning message appears out of nowhere when the zombie process terminates in the background.
Exception KeyboardInterrupt in <module 'threading' from '/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.pyc'> ignored

comment:9 by Zsolt Ero, 10 years ago

Needs documentation: set
Needs tests: set
Patch needs improvement: set

comment:10 by Carl Meyer, 10 years ago

Needs documentation: unset
Needs tests: unset
Patch needs improvement: unset

We usually don't set any of those flags unless the ticket has a patch to begin with.

I'm afraid the only way this ticket is likely to be solved is if someone who can reproduce it tracks down the root cause - and right now the known set of people who can reproduce it includes only yourself :/ Clearly runserver is not behaving correctly on your system, but at this point it's impossible to say whether it's a bug in runserver or something else about your system.

You could experiment with the --noreload and --nothreading options to see how they change the behavior. (Obviously with --noreload it's expected for the server to never auto-reload on changes to .py files, but it might be interesting to know if this changes the shutdown issue you're seeing.)

comment:11 by Zsolt Ero, 10 years ago

I'm sure there'll be other developers with OS X 10.9.5 and Python 2.7.9.

Difference with --noreload:
No zombie process, but the whole server waits after Ctrl+C for quite a while. Like 15 seconds. It'd be interesting to know what is it waiting for. Also, no "Exception KeyboardInterrupt" this way.

--nothreading:

  • This fixed all the problems!
  • Behaves very differently then normal mode: if I save a file, which was already loaded, the server is triggered into an auto reload, simply on saving the file
  • In the threading mode, the auto reload was not triggered like this.

--nothreading --noreload:
Upon Ctrl + C, I couldn't quit the server, but received this:

^C----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 50457)
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Users/user/Dropbox/sync/dev/django/tango/venv/lib/python2.7/site-packages/django/core/servers/basehttp.py", line 129, in __init__
    super(WSGIRequestHandler, self).__init__(*args, **kwargs)
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 655, in __init__
    self.handle()
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/simple_server.py", line 116, in handle
    self.raw_requestline = self.rfile.readline(65537)
  File "/usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 476, in readline
    data = self._sock.recv(self._rbufsize)
KeyboardInterrupt
----------------------------------------

comment:12 by Carl Meyer, 10 years ago

The behavior you describe with --nothreading (where the server reloads immediately upon a file save) is the normal and expected behavior. So something is broken on your system with the runserver threading.

I am sure there are other developers using the same OS X and Python versions, but I doubt they will all be able to reproduce this behavior (or else I think we'd have had many reports much earlier; runserver has had threading for several years). But hopefully someone can reproduce - we'll see!

comment:13 by Zsolt Ero, 10 years ago

Recreated the whole thing from scratch, both in 1.7.4, 1.7.0 and 1.6.10.
Result: bug only in 1.7.x.

Put it into two repos:
https://github.com/hyperknot/django_threading_bug_17
https://github.com/hyperknot/django_threading_bug_16

comment:14 by Tim Graham, 10 years ago

If you could start with the stable/1.7.x branch and use git bisect to bisect the commit where the change happened, that might give some insight. Follow those instructions, but mark commits good or bad manually after you test instead of using git bisect run.

comment:15 by Tim Graham, 10 years ago

Resolution: needsinfo
Status: newclosed
Note: See TracTickets for help on using tickets.
Back to Top