Repository: benoitc/gunicorn

Issue:
Auto restart is not working with gunicorn.workers.gthread.ThreadWorker
Hi,

Using a slightly modified test application so that I can see what is
happening:

```
print '--- started'

def app(environ, start_response):
    """Simplest possible application object"""
    print '* handling request'
    data = 'Hello, World!\n'
    status = '200 OK'
    response_headers = [
        ('Content-type','text/plain'),
        ('Content-Length', str(len(data)))
    ]
    start_response(status, response_headers)
    return iter([data])
```

and running the gunicorn with

```
gunicorn --workers=1 --threads=2 --max-requests=2 test:app
```

I would expect the worker to be restarted after two requests. This does not happen:

```
$ gunicorn --workers=1 --threads=2 --max-requests=2 test:app
[2015-05-15 23:47:19 +0000] [2532] [INFO] Starting gunicorn 19.3.0
[2015-05-15 23:47:19 +0000] [2532] [INFO] Listening at: http://127.0.0.1:8000 (2532)
[2015-05-15 23:47:19 +0000] [2532] [INFO] Using worker: threads
[2015-05-15 23:47:19 +0000] [2537] [INFO] Booting worker with pid: 2537
--- started
* handling request
* handling request
* handling request
* handling request
* handling request
* handling request
```

Expected result: worker restarted after max-requests
Observer result: worker is not restarted

I think the problem is that `self.nr` is used in the `ThreadedWorker` to
count the number of active connections instead the number of reqeuests
the worker has seen. The counter is increased in the `accept()` and
decreased in the `murder_keepalived()`. In the `run()` method there is a condition:

```
# can we accept more connections?
if self.nr < self.worker_connections:
```

but at the same time in `handle_request()`:

```
if self.alive and self.nr >= self.max_requests:
    self.log.info("Autorestarting worker after current request.")
```

so the worker would actually restart if there were more than
`self.max_requets` number of concurrent requests?

In `async.py` and `sync.py` the `self.nr` is used for counting the handled
requests:

```
self.nr += 1
if self.alive and self.nr >= self.max_requests:
    self.log.info("Autorestarting worker after current request.")
```

I think that the `ThreadedWorker` should do the same and use another
variable for counting the concurrent connections.

Version information:

```
bash-4.2$ gunicorn --version
gunicorn (version 19.3.0)
bash-4.2$ python --version
Python 2.7.5
bash-4.2$ pip freeze
futures==3.0.2
-e git+https://github.com/benoitc/gunicorn.git@cc7459d953856d61cd810c1359f78796d181d902#egg=gunicorn-master
pluggy==0.3.0
py==1.4.27
tox==2.0.1
virtualenv==12.1.1
```



Discussion:

Resolving patch:
diff --git a/gunicorn/workers/gthread.py b/gunicorn/workers/gthread.py
--- a/gunicorn/workers/gthread.py
+++ b/gunicorn/workers/gthread.py
@@ -92,6 +92,7 @@ def __init__(self, *args, **kwargs):
         self._lock = None
         self.futures = deque()
         self._keep = deque()
+        self.nr_conns = 0
 
     @classmethod
     def check_config(cls, cfg, log):
@@ -131,7 +132,7 @@ def accept(self, listener):
             client, addr = listener.accept()
             # initialize the connection object
             conn = TConn(self.cfg, listener, client, addr)
-            self.nr += 1
+            self.nr_conns += 1
             # enqueue the job
             self.enqueue_req(conn)
         except socket.error as e:
@@ -170,7 +171,7 @@ def murder_keepalived(self):
                     self._keep.appendleft(conn)
                 break
             else:
-                self.nr -= 1
+                self.nr_conns -= 1
                 # remove the socket from the poller
                 with self._lock:
                     try:
@@ -202,7 +203,7 @@ def run(self):
             self.notify()
 
             # can we accept more connections?
-            if self.nr < self.worker_connections:
+            if self.nr_conns < self.worker_connections:
                 # wait for an event
                 events = self.poller.select(0.02)
                 for key, mask in events:
@@ -253,12 +254,12 @@ def finish_request(self, fs):
                     self.poller.register(conn.sock, selectors.EVENT_READ,
                             partial(self.reuse_connection, conn))
             else:
-                self.nr -= 1
+                self.nr_conns -= 1
                 conn.close()
         except:
             # an exception happened, make sure to close the
             # socket.
-            self.nr -= 1
+            self.nr_conns -= 1
             fs.conn.close()
 
     def handle(self, conn):
@@ -308,7 +309,7 @@ def handle_request(self, req, conn):
             resp, environ = wsgi.create(req, conn.sock, conn.addr,
                     conn.listener.getsockname(), self.cfg)
             environ["wsgi.multithread"] = True
-
+            self.nr += 1
             if self.alive and self.nr >= self.max_requests:
                 self.log.info("Autorestarting worker after current request.")
                 resp.force_close()


Test patch: