def test_multiple_coros(self): evt = Event() results = [] def producer(): results.append('prod') evt.send() def consumer(): results.append('cons1') evt.wait() results.append('cons2') pool = GreenPool(2) done = pool.spawn(consumer) pool.spawn_n(producer) done.wait() self.assertEquals(['cons1', 'prod', 'cons2'], results)
def test_reentrant(self): pool = GreenPool(1) def reenter(): waiter = pool.spawn(lambda a: a, 'reenter') self.assertEqual('reenter', waiter.wait()) outer_waiter = pool.spawn(reenter) outer_waiter.wait() evt = Event() def reenter_async(): pool.spawn_n(lambda a: a, 'reenter') evt.send('done') pool.spawn_n(reenter_async) self.assertEquals('done', evt.wait())
def test_multiple_coros(self): evt = Event() results = [] def producer(): results.append("prod") evt.send() def consumer(): results.append("cons1") evt.wait() results.append("cons2") pool = GreenPool(2) done = pool.spawn(consumer) pool.spawn_n(producer) done.wait() self.assertEquals(["cons1", "prod", "cons2"], results)
def test_reentrant(self): pool = GreenPool(1) def reenter(): waiter = pool.spawn(lambda a: a, "reenter") self.assertEqual("reenter", waiter.wait()) outer_waiter = pool.spawn(reenter) outer_waiter.wait() evt = Event() def reenter_async(): pool.spawn_n(lambda a: a, "reenter") evt.send("done") pool.spawn_n(reenter_async) self.assertEquals("done", evt.wait())
def test_create_contention(self): creates = [0] def sleep_create(): creates[0] += 1 sleep() return "slept" p = pools.Pool(max_size=4, create=sleep_create) def do_get(): x = p.get() self.assertEquals(x, "slept") p.put(x) gp = GreenPool() for i in xrange(100): gp.spawn_n(do_get) gp.waitall() self.assertEquals(creates[0], 4)
def test_create_contention (self): creates = [0] def sleep_create (): creates[0] += 1 sleep() return "slept" p = pools.Pool(max_size = 4, create = sleep_create) def do_get (): x = p.get() self.assertEquals(x, "slept") p.put(x) gp = GreenPool() for i in xrange(100): gp.spawn_n(do_get) gp.waitall() self.assertEquals(creates[0], 4)
def test_spawn_n_2(self): p = GreenPool(2) self.assertEqual(p.free(), 2) r = [] def foo(a): r.append(a) gt = p.spawn(foo, 1) self.assertEqual(p.free(), 1) gt.wait() self.assertEqual(r, [1]) sleep(0) self.assertEqual(p.free(), 2) #Once the pool is exhausted, spawning forces a yield. p.spawn_n(foo, 2) self.assertEqual(1, p.free()) self.assertEqual(r, [1]) p.spawn_n(foo, 3) self.assertEqual(0, p.free()) self.assertEqual(r, [1]) p.spawn_n(foo, 4) self.assertEqual(set(r), set([1, 2, 3])) sleep(0) self.assertEqual(set(r), set([1, 2, 3, 4]))
def test_spawn_n_2(self): p = GreenPool(2) self.assertEqual(p.free(), 2) r = [] def foo(a): r.append(a) gt = p.spawn(foo, 1) self.assertEqual(p.free(), 1) gt.wait() self.assertEqual(r, [1]) sleep(0) self.assertEqual(p.free(), 2) # Once the pool is exhausted, spawning forces a yield. p.spawn_n(foo, 2) self.assertEqual(1, p.free()) self.assertEqual(r, [1]) p.spawn_n(foo, 3) self.assertEqual(0, p.free()) self.assertEqual(r, [1]) p.spawn_n(foo, 4) self.assertEqual(set(r), set([1, 2, 3])) sleep(0) self.assertEqual(set(r), set([1, 2, 3, 4]))
def server(sock, site, log=None, environ=None, max_size=None, max_http_version=DEFAULT_MAX_HTTP_VERSION, protocol=HttpProtocol, server_event=None, minimum_chunk_size=None, log_x_forwarded_for=True, custom_pool=None, keepalive=True, log_output=True, log_format=DEFAULT_LOG_FORMAT, url_length_limit=MAX_REQUEST_LINE, debug=True): """ Start up a wsgi server handling requests from the supplied server socket. This function loops forever. The *sock* object will be closed after server exits, but the underlying file descriptor will remain open, so if you have a dup() of *sock*, it will remain usable. :param sock: Server socket, must be already bound to a port and listening. :param site: WSGI application function. :param log: File-like object that logs should be written to. If not specified, sys.stderr is used. :param environ: Additional parameters that go into the environ dictionary of every request. :param max_size: Maximum number of client connections opened at any time by this server. :param max_http_version: Set to "HTTP/1.0" to make the server pretend it only supports HTTP 1.0. This can help with applications or clients that don't behave properly using HTTP 1.1. :param protocol: Protocol class. Deprecated. :param server_event: Used to collect the Server object. Deprecated. :param minimum_chunk_size: Minimum size in bytes for http chunks. This can be used to improve performance of applications which yield many small strings, though using it technically violates the WSGI spec. :param log_x_forwarded_for: If True (the default), logs the contents of the x-forwarded-for header in addition to the actual client ip address in the 'client_ip' field of the log line. :param custom_pool: A custom GreenPool instance which is used to spawn client green threads. If this is supplied, max_size is ignored. :param keepalive: If set to False, disables keepalives on the server; all connections will be closed after serving one request. :param log_output: A Boolean indicating if the server will log data or not. :param log_format: A python format string that is used as the template to generate log lines. The following values can be formatted into it: client_ip, date_time, request_line, status_code, body_length, wall_seconds. The default is a good example of how to use it. :param url_length_limit: A maximum allowed length of the request url. If exceeded, 414 error is returned. :param debug: True if the server should send exception tracebacks to the clients on 500 errors. If False, the server will respond with empty bodies. """ serv = Server(sock, sock.getsockname(), site, log, environ=environ, max_http_version=max_http_version, protocol=protocol, minimum_chunk_size=minimum_chunk_size, log_x_forwarded_for=log_x_forwarded_for, keepalive=keepalive, log_output=log_output, log_format=log_format, url_length_limit=url_length_limit, debug=debug) if server_event is not None: server_event.send(serv) if max_size is None: max_size = DEFAULT_MAX_SIMULTANEOUS_REQUESTS if custom_pool is not None: pool = custom_pool else: pool = GreenPool(max_size) try: host, port = sock.getsockname()[:2] port = ':%s' % (port, ) if hasattr(sock, 'do_handshake'): scheme = 'https' if port == ':443': port = '' else: scheme = 'http' if port == ':80': port = '' serv.log.write("(%s) wsgi starting up on %s://%s%s/\n" % (os.getpid(), scheme, host, port)) while True: try: client_socket = sock.accept() try: pool.spawn_n(serv.process_request, client_socket) except AttributeError: warnings.warn("wsgi's pool should be an instance of "\ "evy.greenpool.GreenPool, is %s. Please convert your"\ " call site to use GreenPool instead" % type(pool), DeprecationWarning, stacklevel = 2) pool.execute_async(serv.process_request, client_socket) except ACCEPT_EXCEPTIONS, e: if get_errno(e) not in ACCEPT_ERRNO: raise except (KeyboardInterrupt, SystemExit): serv.log.write("wsgi exiting\n") break
def server (sock, site, log = None, environ = None, max_size = None, max_http_version = DEFAULT_MAX_HTTP_VERSION, protocol = HttpProtocol, server_event = None, minimum_chunk_size = None, log_x_forwarded_for = True, custom_pool = None, keepalive = True, log_output = True, log_format = DEFAULT_LOG_FORMAT, url_length_limit = MAX_REQUEST_LINE, debug = True): """ Start up a wsgi server handling requests from the supplied server socket. This function loops forever. The *sock* object will be closed after server exits, but the underlying file descriptor will remain open, so if you have a dup() of *sock*, it will remain usable. :param sock: Server socket, must be already bound to a port and listening. :param site: WSGI application function. :param log: File-like object that logs should be written to. If not specified, sys.stderr is used. :param environ: Additional parameters that go into the environ dictionary of every request. :param max_size: Maximum number of client connections opened at any time by this server. :param max_http_version: Set to "HTTP/1.0" to make the server pretend it only supports HTTP 1.0. This can help with applications or clients that don't behave properly using HTTP 1.1. :param protocol: Protocol class. Deprecated. :param server_event: Used to collect the Server object. Deprecated. :param minimum_chunk_size: Minimum size in bytes for http chunks. This can be used to improve performance of applications which yield many small strings, though using it technically violates the WSGI spec. :param log_x_forwarded_for: If True (the default), logs the contents of the x-forwarded-for header in addition to the actual client ip address in the 'client_ip' field of the log line. :param custom_pool: A custom GreenPool instance which is used to spawn client green threads. If this is supplied, max_size is ignored. :param keepalive: If set to False, disables keepalives on the server; all connections will be closed after serving one request. :param log_output: A Boolean indicating if the server will log data or not. :param log_format: A python format string that is used as the template to generate log lines. The following values can be formatted into it: client_ip, date_time, request_line, status_code, body_length, wall_seconds. The default is a good example of how to use it. :param url_length_limit: A maximum allowed length of the request url. If exceeded, 414 error is returned. :param debug: True if the server should send exception tracebacks to the clients on 500 errors. If False, the server will respond with empty bodies. """ serv = Server(sock, sock.getsockname(), site, log, environ = environ, max_http_version = max_http_version, protocol = protocol, minimum_chunk_size = minimum_chunk_size, log_x_forwarded_for = log_x_forwarded_for, keepalive = keepalive, log_output = log_output, log_format = log_format, url_length_limit = url_length_limit, debug = debug) if server_event is not None: server_event.send(serv) if max_size is None: max_size = DEFAULT_MAX_SIMULTANEOUS_REQUESTS if custom_pool is not None: pool = custom_pool else: pool = GreenPool(max_size) try: host, port = sock.getsockname()[:2] port = ':%s' % (port, ) if hasattr(sock, 'do_handshake'): scheme = 'https' if port == ':443': port = '' else: scheme = 'http' if port == ':80': port = '' serv.log.write("(%s) wsgi starting up on %s://%s%s/\n" % ( os.getpid(), scheme, host, port)) while True: try: client_socket = sock.accept() try: pool.spawn_n(serv.process_request, client_socket) except AttributeError: warnings.warn("wsgi's pool should be an instance of "\ "evy.greenpool.GreenPool, is %s. Please convert your"\ " call site to use GreenPool instead" % type(pool), DeprecationWarning, stacklevel = 2) pool.execute_async(serv.process_request, client_socket) except ACCEPT_EXCEPTIONS, e: if get_errno(e) not in ACCEPT_ERRNO: raise except (KeyboardInterrupt, SystemExit): serv.log.write("wsgi exiting\n") break