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 |