Statistics
| Branch: | Tag: | Revision:

root / snf-pithos-backend / pithos / workers / gevent_archipelago.py @ 1c6f4d42

History | View | Annotate | Download (5.3 kB)

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