Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / workers / gevent_archipelago.py @ 809b482a

History | View | Annotate | Download (5.3 kB)

1 91b63720 Chrysostomos Nanakos
# -*- coding: utf-8 -
2 91b63720 Chrysostomos Nanakos
#
3 91b63720 Chrysostomos Nanakos
# Copyright 2013 GRNET S.A. All rights reserved.
4 91b63720 Chrysostomos Nanakos
#
5 91b63720 Chrysostomos Nanakos
# Redistribution and use in source and binary forms, with or
6 91b63720 Chrysostomos Nanakos
# without modification, are permitted provided that the following
7 91b63720 Chrysostomos Nanakos
# conditions are met:
8 91b63720 Chrysostomos Nanakos
#
9 91b63720 Chrysostomos Nanakos
#   1. Redistributions of source code must retain the above
10 91b63720 Chrysostomos Nanakos
#      copyright notice, this list of conditions and the following
11 91b63720 Chrysostomos Nanakos
#      disclaimer.
12 91b63720 Chrysostomos Nanakos
#
13 91b63720 Chrysostomos Nanakos
#   2. Redistributions in binary form must reproduce the above
14 91b63720 Chrysostomos Nanakos
#      copyright notice, this list of conditions and the following
15 91b63720 Chrysostomos Nanakos
#      disclaimer in the documentation and/or other materials
16 91b63720 Chrysostomos Nanakos
#      provided with the distribution.
17 91b63720 Chrysostomos Nanakos
#
18 91b63720 Chrysostomos Nanakos
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 91b63720 Chrysostomos Nanakos
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 91b63720 Chrysostomos Nanakos
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 91b63720 Chrysostomos Nanakos
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 91b63720 Chrysostomos Nanakos
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 91b63720 Chrysostomos Nanakos
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 91b63720 Chrysostomos Nanakos
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 91b63720 Chrysostomos Nanakos
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 91b63720 Chrysostomos Nanakos
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 91b63720 Chrysostomos Nanakos
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 91b63720 Chrysostomos Nanakos
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 91b63720 Chrysostomos Nanakos
# POSSIBILITY OF SUCH DAMAGE.
30 91b63720 Chrysostomos Nanakos
#
31 91b63720 Chrysostomos Nanakos
# The views and conclusions contained in the software and
32 91b63720 Chrysostomos Nanakos
# documentation are those of the authors and should not be
33 91b63720 Chrysostomos Nanakos
# interpreted as representing official policies, either expressed
34 91b63720 Chrysostomos Nanakos
# or implied, of GRNET S.A.
35 91b63720 Chrysostomos Nanakos
36 91b63720 Chrysostomos Nanakos
37 91b63720 Chrysostomos Nanakos
from __future__ import with_statement
38 91b63720 Chrysostomos Nanakos
39 91b63720 Chrysostomos Nanakos
import os
40 91b63720 Chrysostomos Nanakos
import sys
41 91b63720 Chrysostomos Nanakos
from datetime import datetime
42 91b63720 Chrysostomos Nanakos
43 91b63720 Chrysostomos Nanakos
# workaround on osx, disable kqueue
44 91b63720 Chrysostomos Nanakos
if sys.platform == "darwin":
45 91b63720 Chrysostomos Nanakos
    os.environ['EVENT_NOKQUEUE'] = "1"
46 91b63720 Chrysostomos Nanakos
47 91b63720 Chrysostomos Nanakos
try:
48 91b63720 Chrysostomos Nanakos
    import gevent
49 91b63720 Chrysostomos Nanakos
except ImportError:
50 91b63720 Chrysostomos Nanakos
    raise RuntimeError("You need gevent installed to use this worker.")
51 91b63720 Chrysostomos Nanakos
from gevent.pool import Pool
52 91b63720 Chrysostomos Nanakos
from gevent.server import StreamServer
53 91b63720 Chrysostomos Nanakos
from gevent import pywsgi
54 91b63720 Chrysostomos Nanakos
from gevent import select
55 91b63720 Chrysostomos Nanakos
56 91b63720 Chrysostomos Nanakos
import gunicorn
57 91b63720 Chrysostomos Nanakos
from gunicorn.workers.async import AsyncWorker
58 91b63720 Chrysostomos Nanakos
59 91b63720 Chrysostomos Nanakos
VERSION = "gevent/%s gunicorn/%s" % (gevent.__version__, gunicorn.__version__)
60 91b63720 Chrysostomos Nanakos
61 91b63720 Chrysostomos Nanakos
BASE_WSGI_ENV = {
62 91b63720 Chrysostomos Nanakos
    'GATEWAY_INTERFACE': 'CGI/1.1',
63 91b63720 Chrysostomos Nanakos
    'SERVER_SOFTWARE': VERSION,
64 91b63720 Chrysostomos Nanakos
    'SCRIPT_NAME': '',
65 91b63720 Chrysostomos Nanakos
    'wsgi.version': (1, 0),
66 91b63720 Chrysostomos Nanakos
    'wsgi.multithread': False,
67 91b63720 Chrysostomos Nanakos
    'wsgi.multiprocess': False,
68 91b63720 Chrysostomos Nanakos
    'wsgi.run_once': False
69 91b63720 Chrysostomos Nanakos
}
70 91b63720 Chrysostomos Nanakos
71 91b63720 Chrysostomos Nanakos
72 91b63720 Chrysostomos Nanakos
class GeventArchipelagoWorker(AsyncWorker):
73 91b63720 Chrysostomos Nanakos
74 91b63720 Chrysostomos Nanakos
    server_class = None
75 91b63720 Chrysostomos Nanakos
    wsgi_handler = None
76 91b63720 Chrysostomos Nanakos
77 91b63720 Chrysostomos Nanakos
    def __init__(self, *args, **kwargs):
78 91b63720 Chrysostomos Nanakos
        super(GeventArchipelagoWorker, self).__init__(*args, **kwargs)
79 91b63720 Chrysostomos Nanakos
        self.worker_id = args[0]
80 91b63720 Chrysostomos Nanakos
81 91b63720 Chrysostomos Nanakos
    @classmethod
82 91b63720 Chrysostomos Nanakos
    def setup(cls):
83 91b63720 Chrysostomos Nanakos
        from gevent import monkey
84 91b63720 Chrysostomos Nanakos
        monkey.noisy = False
85 91b63720 Chrysostomos Nanakos
        monkey.patch_all()
86 91b63720 Chrysostomos Nanakos
87 91b63720 Chrysostomos Nanakos
    def timeout_ctx(self):
88 91b63720 Chrysostomos Nanakos
        return gevent.Timeout(self.cfg.keepalive, False)
89 91b63720 Chrysostomos Nanakos
90 91b63720 Chrysostomos Nanakos
    def run(self):
91 91b63720 Chrysostomos Nanakos
        self.socket.setblocking(1)
92 91b63720 Chrysostomos Nanakos
93 91b63720 Chrysostomos Nanakos
        pool = Pool(self.worker_connections)
94 91b63720 Chrysostomos Nanakos
        if self.server_class is not None:
95 91b63720 Chrysostomos Nanakos
            server = self.server_class(
96 91b63720 Chrysostomos Nanakos
                self.socket, application=self.wsgi, spawn=pool, log=self.log,
97 91b63720 Chrysostomos Nanakos
                handler_class=self.wsgi_handler)
98 91b63720 Chrysostomos Nanakos
        else:
99 91b63720 Chrysostomos Nanakos
            server = StreamServer(self.socket, handle=self.handle, spawn=pool)
100 91b63720 Chrysostomos Nanakos
101 91b63720 Chrysostomos Nanakos
        server.start()
102 91b63720 Chrysostomos Nanakos
        try:
103 91b63720 Chrysostomos Nanakos
            while self.alive:
104 91b63720 Chrysostomos Nanakos
                self.notify()
105 91b63720 Chrysostomos Nanakos
                if self.ppid != os.getppid():
106 91b63720 Chrysostomos Nanakos
                    self.log.info("Parent changed, shutting down: %s", self)
107 91b63720 Chrysostomos Nanakos
                    break
108 91b63720 Chrysostomos Nanakos
109 91b63720 Chrysostomos Nanakos
                gevent.sleep(1.0)
110 91b63720 Chrysostomos Nanakos
111 91b63720 Chrysostomos Nanakos
        except KeyboardInterrupt:
112 91b63720 Chrysostomos Nanakos
            pass
113 91b63720 Chrysostomos Nanakos
114 91b63720 Chrysostomos Nanakos
        try:
115 91b63720 Chrysostomos Nanakos
            # Try to stop connections until timeout
116 91b63720 Chrysostomos Nanakos
            self.notify()
117 91b63720 Chrysostomos Nanakos
            server.stop(timeout=self.cfg.graceful_timeout)
118 91b63720 Chrysostomos Nanakos
        except:
119 91b63720 Chrysostomos Nanakos
            pass
120 91b63720 Chrysostomos Nanakos
121 91b63720 Chrysostomos Nanakos
    def handle_request(self, *args):
122 91b63720 Chrysostomos Nanakos
        try:
123 91b63720 Chrysostomos Nanakos
            super(GeventArchipelagoWorker, self).handle_request(*args)
124 91b63720 Chrysostomos Nanakos
        except gevent.GreenletExit:
125 91b63720 Chrysostomos Nanakos
            pass
126 91b63720 Chrysostomos Nanakos
127 91b63720 Chrysostomos Nanakos
    if gevent.version_info[0] == 0:
128 91b63720 Chrysostomos Nanakos
129 91b63720 Chrysostomos Nanakos
        def init_process(self):
130 91b63720 Chrysostomos Nanakos
            #gevent 0.13 and older doesn't reinitialize dns for us after
131 91b63720 Chrysostomos Nanakos
            #forking here's the workaround
132 91b63720 Chrysostomos Nanakos
            import gevent.core
133 91b63720 Chrysostomos Nanakos
            gevent.core.dns_shutdown(fail_requests=1)
134 91b63720 Chrysostomos Nanakos
            gevent.core.dns_init()
135 91b63720 Chrysostomos Nanakos
            super(GeventArchipelagoWorker, self).init_process()
136 91b63720 Chrysostomos Nanakos
137 91b63720 Chrysostomos Nanakos
138 91b63720 Chrysostomos Nanakos
class GeventResponse(object):
139 91b63720 Chrysostomos Nanakos
140 91b63720 Chrysostomos Nanakos
    status = None
141 91b63720 Chrysostomos Nanakos
    headers = None
142 91b63720 Chrysostomos Nanakos
    response_length = None
143 91b63720 Chrysostomos Nanakos
144 91b63720 Chrysostomos Nanakos
    def __init__(self, status, headers, clength):
145 91b63720 Chrysostomos Nanakos
        self.status = status
146 91b63720 Chrysostomos Nanakos
        self.headers = headers
147 91b63720 Chrysostomos Nanakos
        self.response_length = clength
148 91b63720 Chrysostomos Nanakos
149 91b63720 Chrysostomos Nanakos
150 91b63720 Chrysostomos Nanakos
class PyWSGIHandler(pywsgi.WSGIHandler):
151 91b63720 Chrysostomos Nanakos
152 91b63720 Chrysostomos Nanakos
    def log_request(self):
153 91b63720 Chrysostomos Nanakos
        start = datetime.fromtimestamp(self.time_start)
154 91b63720 Chrysostomos Nanakos
        finish = datetime.fromtimestamp(self.time_finish)
155 91b63720 Chrysostomos Nanakos
        response_time = finish - start
156 91b63720 Chrysostomos Nanakos
        resp = GeventResponse(self.status, self.response_headers,
157 91b63720 Chrysostomos Nanakos
                              self.response_length)
158 91b63720 Chrysostomos Nanakos
        req_headers = [h.split(":", 1) for h in self.headers.headers]
159 91b63720 Chrysostomos Nanakos
        self.server.log.access(resp, req_headers, self.environ, response_time)
160 91b63720 Chrysostomos Nanakos
161 91b63720 Chrysostomos Nanakos
    def get_environ(self):
162 91b63720 Chrysostomos Nanakos
        env = super(PyWSGIHandler, self).get_environ()
163 91b63720 Chrysostomos Nanakos
        env['gunicorn.sock'] = self.socket
164 91b63720 Chrysostomos Nanakos
        env['RAW_URI'] = self.path
165 91b63720 Chrysostomos Nanakos
        return env
166 91b63720 Chrysostomos Nanakos
167 91b63720 Chrysostomos Nanakos
168 91b63720 Chrysostomos Nanakos
class PyWSGIServer(pywsgi.WSGIServer):
169 91b63720 Chrysostomos Nanakos
    base_env = BASE_WSGI_ENV
170 91b63720 Chrysostomos Nanakos
171 91b63720 Chrysostomos Nanakos
172 91b63720 Chrysostomos Nanakos
class GeventPyWSGIWorker(GeventArchipelagoWorker):
173 91b63720 Chrysostomos Nanakos
    "The Gevent StreamServer based workers."
174 91b63720 Chrysostomos Nanakos
    server_class = PyWSGIServer
175 91b63720 Chrysostomos Nanakos
    wsgi_handler = PyWSGIHandler