Repository: benoitc/gunicorn

Issue:
Reloading sometimes gives a TypeError: 'NoneType' object is not callable
I'm running a custom app (subclass of `BaseApplication`) with reload set to True. In some situations, changing a file causes the following traceback:

```
Exception in thread Thread-1 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/maxm/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/maxm/lib/python2.7/site-packages/gunicorn/reloader.py", line 52, in run
  File "/usr/maxm/lib/python2.7/site-packages/gunicorn/workers/base.py", line 87, in changed
<type 'exceptions.TypeError'>: 'NoneType' object is not callable
```

It's intermittent; I can sometimes reproduce it several times in a row by touching the same file, and then it stops happening. It certainly doesn't seem to interfere with the reloading behavior.

Line 87 is only `raise SystemExit()`. But line 86 is `os.kill(self.pid, signal.SIGQUIT)`, so I think what's happening is that the interpreter has started to tear down the environment and `SystemExit` has become `None`. (See also [this](http://article.gmane.org/gmane.comp.python.general/387087/) mailing list post.) 

Anything I can do about this?



Discussion:
I've seen this before. It's harmless, beside the log noise. Your diagnosis of the cause is correct, I think.

If you would like, you could try this patch, but I'm not sure it will be enough:

``` patch
diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py
index 8f75805..b19fd42 100644
--- a/gunicorn/workers/base.py
+++ b/gunicorn/workers/base.py
@@ -84,8 +84,9 @@ class Worker(object):
         if self.cfg.reload:
             def changed(fname):
                 self.log.info("Worker reloading: %s modified", fname)
+                exception = SystemExit()
                 os.kill(self.pid, signal.SIGQUIT)
-                raise SystemExit()
+                raise exception
             Reloader(callback=changed).start()

         # set environment' variables
```

@inklesspen did you try the patch?

Sorry, no; we've been ignoring the situation since it's just noise. I can try it out on Monday.

Sorry about the delay. I finally remembered to test this today. It makes a difference, but it doesn't entirely solve the problem:

```
[2014-12-17 15:37:32 +0000] [10398] [INFO] Worker reloading: /usr/axm/lib/python2.7/site-packages/valuationlib/application.py modified
[2014-12-17 15:37:32 +0000] [10398] [INFO] Worker exiting (pid: 10398)
[2014-12-17 15:37:32 +0000] [10427] [INFO] Booting worker with pid: 10427
[2014-12-17 15:37:35 +0000] [10427] [INFO] Worker reloading: /usr/axm/lib/python2.7/site-packages/valuationlib/application.py modified
[2014-12-17 15:37:35 +0000] [10427] [INFO] Worker exiting (pid: 10427)
[2014-12-17 15:37:35 +0000] [10439] [INFO] Booting worker with pid: 10439
[2014-12-17 15:37:38 +0000] [10439] [INFO] Worker reloading: /usr/axm/lib/python2.7/site-packages/valuationlib/application.py modified
[2014-12-17 15:37:38 +0000] [10439] [INFO] Worker exiting (pid: 10439)
Exception in thread Thread-1 (most likely raised during interpreter shutdown):
Traceback (most recent call last):
  File "/usr/maxm/lib/python2.7/threading.py", line 551, in __bootstrap_inner
  File "/usr/maxm/lib/python2.7/site-packages/gunicorn/reloader.py", line 52, in run
  File "/usr/maxm/lib/python2.7/site-packages/gunicorn/workers/base.py", line 88, in changed
<type 'exceptions.SystemExit'>:
[2014-12-17 15:37:38 +0000] [10448] [INFO] Booting worker with pid: 10448
```

So the error can still occur, but the exception at least makes it more obvious nothing is really wrong.

I wonder, do we need the worker to send to send `SIGQUIT` to itself or could we just raise the exception and let the Python runtime kill it?


Resolving patch:
diff --git a/gunicorn/workers/base.py b/gunicorn/workers/base.py
--- a/gunicorn/workers/base.py
+++ b/gunicorn/workers/base.py
@@ -87,7 +87,6 @@ def init_process(self):
             def changed(fname):
                 self.log.info("Worker reloading: %s modified", fname)
                 os.kill(self.pid, signal.SIGQUIT)
-                raise SystemExit()
             Reloader(callback=changed).start()
 
         # set environment' variables


Test patch: