{ "info": { "author": "Giovanni Bajo", "author_email": "rasky@develer.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: No Input/Output (Daemon)", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 2", "Topic :: Software Development" ], "description": "geventconnpool\n==============\nThis package implements a generic TCP connection pool for gevent-based\napplications. It can be used every time your program needs to connnect to\nan external service through a TCP-based protocol (including all HTTP protocols\nlike REST APIs), and you want your process to keep and manage a pool of\nconnections to the remote endpoint.\n\nA typical scenario might be a gunicorn-based web application with gevent backend,\nthat accesses remote service through HTTPS APIs. In this case, using the pool\nshorten the request and minimize the latency because the pool keeps open\nconnections to the remote endpoints, and it is not necessary to do a full SSL\nhandshake every time we need to issue a command.\n\nQuickstart\n==========\nTo install the package, use pip::\n\n $ pip install geventconnpool\n\nor easy_install::\n\n $ easy_install geventconnpool\n\nYou need to derive from ``ConnectionPool`` and reimplement ``_new_connection``,\nto specify how to open a connection to the remove site. For instance:\n\n.. code-block:: python\n\n from geventconnpool import ConnectionPool\n from gevent import socket\n\n class MyPool(ConnectionPool):\n def _new_connection(self):\n return socket.create_connection(('test.example.org', 2485))\n\nIn this case, we're simply opening a TCP connection to a specified peer.\n\nThe pool can be istantiated by specifying how many connections we want to\nkeep open at the same time:\n\n.. code-block:: python\n\n pool = MyPool(20) # always keep 20 connections open\n\n\nTo access a connection within the pool:\n\n.. code-block:: python\n\n with pool.get() as c:\n c.send(\"PING\\n\")\n if c.recv(5) != \"PONG\\n\":\n raise socket.error(\"something awful happened\")\n\nIf the context is quit through a ``socket.error`` exception, the connection is\ndiscarded and a new open is opened in background, to keep the pool always full\nof valid connections. Any other exception does not have a special meaning, and\nthe connection will be reinserted into the pool to be reused later.\n\nIf your application/library uses exceptions that do not derive from\n``socket.error`` to signify connection errors (``imaplib`` is one example),\nyou can override which exceptions are treated as triggering discards:\n\n.. code-block:: python\n\n pool = MyPool(20, exc_classes=(socket.error, imaplib.IMAP4.error))\n\nAutomatic retrying\n==================\nIf you want to be resilent to temporary network errors, you can use the ``retry``\ndecorator that will re-execute the function if it is quit with a ``socket.error``\nexception:\n\n.. code-block:: python\n\n from geventconnpool import retry\n\n @retry\n def senddata(data):\n with pool.get() as c:\n c.send(data)\n if c.recv(2) != \"OK\":\n raise socket.error(\"something awful happened\")\n\nSince the pool discards the connections when a ``socket.error`` exception is\ngenerated, the net effect of `retry` is that a different connection will be\nused for each attempt.\n\nThe ``retry`` decorator has some extra features which are disabled by default.\nIf you pass it a logger, it will log each attempt. You can also specify a\nmaximum number of attempts, an interval to wait between successive attempts,\nand which specific exception classes to trigger retries on. Log messages and\nlevels are customizable.\n\n.. code-block:: python\n\n import logging\n logging.basicConfig()\n log = logging.getLogger()\n\n from geventconnpool import retry\n\n @retry(exc_classes=(socket.error, imaplib.IMAP4.error), logger=log,\n max_failures=5, interval=2)\n def senddata(data):\n with pool.get() as c:\n typ, data = c.select('INBOX')\n\nIf you wish to codify a set of options to ``retry`` into your code, consider\nusing ``functools.partial``.\n\nAdvanced connection examples\n============================\nWhen implement a connection pool, it is advisable to perform all the\ninitialization phases of the application protocol within the ``_new_connection``\ncallback. For instance, a protocol might allow to switch to TLS\n(with a STARTTLS-like) and then require authentication:\n\n.. code-block:: python\n\n from geventconnpool import ConnectionPool\n from gevent import socket, ssl\n\n class MyPool(ConnectionPool):\n def _new_connection(self):\n s = socket.create_connection(('test.example.org', 2485))\n s.send(\"STARTTLS\\n\")\n res = s.recv(3)\n if res == \"OK\\n\":\n s = ssl.wrap_socket(s)\n elif res == \"NO\\n\":\n pass\n else:\n raise socket.error(\"invalid response to STARTTLS\")\n\n s.send(\"LOGIN: %s\\n\" % MY_LOGIN_NAME);\n s.send(\"PASS: %s\\n\" % MY_PASS);\n res = s.recv(2)\n if res != \"OK\":\n raise socket.error(\"authentication failed\")\n return s\n\nAs you can see, it is possible to simply raise ``socket.error`` if something\nwent wrong. The pool is resistant to temporary connection errors and will retry\nautomatically to estabilish new connections later.\n\nAnother common situation might involve the usage of third-party libraries like for\ninstance using `boto `_ to connect to\nAmazon AWS:\n\n.. code-block:: python\n\n from geventconnpool import ConnectionPool\n import boto\n from boto.exception import NoAuthHanlder\n\n class UsersPool(ConnectionPool):\n def _new_connection(self):\n try:\n c = boto.connect_dynamodb(MY_AWS_KEY_ID, MY_AWS_SECRET_KEY)\n return c.get_table(\"users\")\n except:\n raise socket.error(\"error connecting to AWS\")\n\nIn this case, we don't only connect to AWS and authenticate, but we also open\na specific table and return a reference to that table. In fact, it is not\nnecessary for the return value of ``_new_connection()`` to be a socket (or\nsocket-like): ``ConnectionPool`` treats it as a black.box and return it when\n``get`` is called.\n\n.. note:: boto has an internal connection pool, but it is only used to be\n fully-thread safe, and does not preemptively open the connections,\n authenticate, and perform initialization. This means that it still makes\n sense to use ``ConnectionPool`` to minimize the latency when communicating\n to AWS.\n\nKeepalive\n=========\nSome protocols or networks might require a keepalive mechanism to keep a\nconnection open if it is idle. For instance, the remote peer, a firewall or a\nload-balancer might close a connection if it is idle for too long.\n\nSometimes, it is sufficient to rely on the standard TCP-level keeaplive, that\ncan be turned on any TCP socket:\n\n.. code-block:: python\n\n from geventconnpool import ConnectionPool\n from gevent import socket\n\n class MyPool(ConnectionPool):\n def _new_connection(self):\n s = socket.create_connection(('test.example.org', 2485))\n s._sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)\n return s\n\nThe TCP keepalive uses ACK packets to continously communicating with the remote\npeer. To tune the keepalive parameters (delay between ACKs, number of unanswered\nACKs to consider the connnection dropped, etc.), you need to tweak with the\nproc filesystem (yes, it's a global per-computer configuration).\n\nAlternatively, it is possible to implement an application-level keepalive\nby implemening the ``_keepalive`` method and specifying the keepalive frequency\nin the constructor:\n\n.. code-block:: python\n\n from geventconnpool import ConnectionPool\n from gevent import socket\n\n class MyPool(ConnectionPool):\n def _new_connection(self):\n return socket.create_connection(('test.example.org', 2485))\n\n def _keepalive(self, c):\n c.send(\"PING\\n\")\n if c.recv(5) != \"PONG\\n\":\n raise socket.error\n\n pool = MyPool(20, keepalive=30)\n\nThe above code uses a keepalive based on an application-level command (PING),\nand specifies that it should be executed every 30 seconds (per each connection).\n\n``_keepalive`` should raise ``socket.error`` to communicate that the connection\nappears to be broken and should be discarded by the pool.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/rasky/geventconnpool", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "geventconnpool", "package_url": "https://pypi.org/project/geventconnpool/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/geventconnpool/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/rasky/geventconnpool" }, "release_url": "https://pypi.org/project/geventconnpool/0.2.1/", "requires_dist": null, "requires_python": null, "summary": "TCP connection pool for gevent", "version": "0.2.1" }, "last_serial": 1112490, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "5e84460911475d0870e5c9ec59ea5f3b", "sha256": "44816247556971424e0527a81603bfc8b9998f25cf65b017cfec5d63770defe2" }, "downloads": -1, "filename": "geventconnpool-0.1.tar.gz", "has_sig": false, "md5_digest": "5e84460911475d0870e5c9ec59ea5f3b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2318, "upload_time": "2013-01-11T10:18:31", "url": "https://files.pythonhosted.org/packages/a2/77/b6357f62c733f6e2fc306040da42b3f38ff30f950e61017e27387ee232e9/geventconnpool-0.1.tar.gz" } ], "0.1a": [ { "comment_text": "", "digests": { "md5": "7317c86eeb6e9679e8797cdf62e6c979", "sha256": "b2db31a84ff4e839513e6bdd43dee44f08e6a431a62657488f192cbbfc64120a" }, "downloads": -1, "filename": "geventconnpool-0.1a.tar.gz", "has_sig": true, "md5_digest": "7317c86eeb6e9679e8797cdf62e6c979", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4934, "upload_time": "2013-01-11T10:23:38", "url": "https://files.pythonhosted.org/packages/90/a7/daa029a61bf9bc14ab614b456b825708792e9a2e566bc2c1741461b71830/geventconnpool-0.1a.tar.gz" } ], "0.1b": [ { "comment_text": "", "digests": { "md5": "37bc94b24db911b66d08c27a3913fda6", "sha256": "584e21123c476aefdd40f4cbf352c182b660782c980c4723f16b6cb1cacc055e" }, "downloads": -1, "filename": "geventconnpool-0.1b.tar.gz", "has_sig": true, "md5_digest": "37bc94b24db911b66d08c27a3913fda6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6112, "upload_time": "2013-01-12T16:37:05", "url": "https://files.pythonhosted.org/packages/25/9d/9daac00dd0ac67c54042a6ab3677ec6b1efa6b31ab639c69c851de1ed685/geventconnpool-0.1b.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "0485de7a0642d226823dcce3e60a7ef7", "sha256": "1b82d31b36461201a6f7555e350c2b9438b0780b7906a743529b0dcc157074e0" }, "downloads": -1, "filename": "geventconnpool-0.2.tar.gz", "has_sig": true, "md5_digest": "0485de7a0642d226823dcce3e60a7ef7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6116, "upload_time": "2013-01-30T11:39:35", "url": "https://files.pythonhosted.org/packages/06/a4/b700db7b09ed6f8913a2ba6722d55f14ded927c7da3b97236f2d86e6e6ca/geventconnpool-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "e6d3acc866d9bc79ce215f593fd43e91", "sha256": "d80ba45260c4ea6fad8569397f5f5f4ada4a7d2a18fcb8ea1dca82f32fbcddc9" }, "downloads": -1, "filename": "geventconnpool-0.2.1.tar.gz", "has_sig": true, "md5_digest": "e6d3acc866d9bc79ce215f593fd43e91", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6862, "upload_time": "2014-06-03T10:39:46", "url": "https://files.pythonhosted.org/packages/12/9e/20c1203fb5b23332179a438997249ae89107c1a162b2c9f32f49ad030883/geventconnpool-0.2.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e6d3acc866d9bc79ce215f593fd43e91", "sha256": "d80ba45260c4ea6fad8569397f5f5f4ada4a7d2a18fcb8ea1dca82f32fbcddc9" }, "downloads": -1, "filename": "geventconnpool-0.2.1.tar.gz", "has_sig": true, "md5_digest": "e6d3acc866d9bc79ce215f593fd43e91", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6862, "upload_time": "2014-06-03T10:39:46", "url": "https://files.pythonhosted.org/packages/12/9e/20c1203fb5b23332179a438997249ae89107c1a162b2c9f32f49ad030883/geventconnpool-0.2.1.tar.gz" } ] }