{ "info": { "author": "Malthe Borch", "author_email": "mborch@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: Science/Research", "Intended Audience :: System Administrators", "License :: OSI Approved :: BSD License", "Operating System :: POSIX", "Programming Language :: Python", "Topic :: Internet", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Distributed Computing", "Topic :: System :: Systems Administration" ], "description": "PQ\n**\n\nA transactional queue system for PostgreSQL written in Python.\n\n.. figure:: https://pq.readthedocs.org/en/latest/_static/intro.svg\n :alt: PQ does the job!\n\nIt allows you to push and pop items in and out of a queue in various\nways and also provides two scheduling options: delayed processing and\nprioritization.\n\nThe system uses a single table that holds all jobs across queues; the\nspecifics are easy to customize.\n\nThe system currently supports only the `psycopg2\n`_ database driver - or\n`psycopg2cffi `_ for PyPy.\n\nThe basic queue implementation is similar to Ryan Smith's\n`queue_classic `_\nlibrary written in Ruby, but uses `SKIP LOCKED\n`_\nfor concurrency control.\n\nIn terms of performance, the implementation clock in at about 1,000\noperations per second. Using the `PyPy `_\ninterpreter, this scales linearly with the number of cores available.\n\n\nGetting started\n===============\n\nAll functionality is encapsulated in a single class ``PQ``.\n\n ``class PQ(conn=None, pool=None, table='queue', debug=False)``\n\nExample usage:\n\n.. code-block:: python\n\n from psycopg2 import connect\n from pq import PQ\n\n conn = connect('dbname=example user=postgres')\n pq = PQ(conn)\n\nFor multi-threaded operation, use a connection pool such as\n``psycopg2.pool.ThreadedConnectionPool``.\n\nYou probably want to make sure your database is created with the\n``utf-8`` encoding.\n\nTo create and configure the queue table, call the ``create()`` method.\n\n.. code-block:: python\n\n pq.create()\n\nThe table name defaults to ``'queue'``. To use a different name, pass\nit as a string value as the ``table`` argument for the ``PQ`` class\n(illustrated above).\n\n\nQueues\n======\n\nThe ``pq`` object exposes queues through Python's dictionary\ninterface:\n\n.. code-block:: python\n\n queue = pq['apples']\n\nThe ``queue`` object provides ``get`` and ``put`` methods as explained\nbelow, and in addition, it also works as a context manager where it\nmanages a transaction:\n\n.. code-block:: python\n\n with queue as cursor:\n ...\n\nThe statements inside the context manager are either committed as a\ntransaction or rejected, atomically. This is useful when a queue is\nused to manage jobs because it allows you to retrieve a job from the\nqueue, perform a job and write a result, with transactional\nsemantics.\n\nMethods\n=======\n\nUse the ``put(data)`` method to insert an item into the queue. It\ntakes a JSON-compatible object such as a Python dictionary:\n\n.. code-block:: python\n\n queue.put({'kind': 'Cox'})\n queue.put({'kind': 'Arthur Turner'})\n queue.put({'kind': 'Golden Delicious'})\n\nItems are pulled out of the queue using ``get(block=True)``. The\ndefault behavior is to block until an item is available with a default\ntimeout of one second after which a value of ``None`` is returned.\n\n.. code-block:: python\n\n def eat(kind):\n print 'umm, %s apples taste good.' % kind\n\n job = queue.get()\n eat(**job.data)\n\nThe ``job`` object provides additional metadata in addition to the\n``data`` attribute as illustrated by the string representation:\n\n >>> job\n \n\nThe ``get`` operation is also available through iteration:\n\n.. code-block:: python\n\n for job in queue:\n if job is None:\n break\n\n eat(**job.data)\n\nThe iterator blocks if no item is available. Again, there is a default\ntimeout of one second, after which the iterator yields a value of\n``None``.\n\nAn application can then choose to break out of the loop, or wait again\nfor an item to be ready.\n\n.. code-block:: python\n\n for job in queue:\n if job is not None:\n eat(**job.data)\n\n # This is an infinite loop!\n\n\nScheduling\n==========\n\nItems can be scheduled such that they're not pulled until a later\ntime:\n\n.. code-block:: python\n\n queue.put({'kind': 'Cox'}, '5m')\n\nIn this example, the item is ready for work five minutes later. The\nmethod also accepts ``datetime`` and ``timedelta`` objects.\n\n\nPriority\n========\n\nIf some items are more important than others, a time expectation can\nbe expressed:\n\n.. code-block:: python\n\n queue.put({'kind': 'Cox'}, expected_at='5m')\n\nThis tells the queue processor to give priority to this item over an\nitem expected at a later time, and conversely, to prefer an item with\nan earlier expected time. Note that items without a set priority are\npulled last.\n\nThe scheduling and priority options can be combined:\n\n.. code-block:: python\n\n queue.put({'kind': 'Cox'}, '1h', '2h')\n\nThis item won't be pulled out until after one hour, and even then,\nit's only processed subject to it's priority of two hours.\n\n\nEncoding and decoding\n=====================\n\nThe task data is encoded and decoded into JSON using the built-in\n`json` module. If you want to use a different implementation or need\nto configure this, pass `encode` and/or `decode` arguments to the `PQ`\nconstructor.\n\n\nPickles\n=======\n\nIf a queue name is provided as ``/pickle``\n(e.g. ``'jobs/pickle'``), items are automatically pickled and\nunpickled using Python's built-in ``cPickle`` module:\n\n.. code-block:: python\n\n queue = pq['apples/pickle']\n\n class Apple(object):\n def __init__(self, kind):\n self.kind = kind\n\n queue.put(Apple('Cox'))\n\nThis allows you to store most objects without having to add any\nfurther serialization code.\n\nThe old pickle protocol ``0`` is used to ensure the pickled data is\nencoded as ``ascii`` which should be compatible with any database\nencoding. Note that the pickle data is still wrapped as a JSON string at the\ndatabase level.\n\nWhile using the pickle protocol is an easy way to serialize objects,\nfor advanced users t might be better to use JSON serialization\ndirectly on the objects, using for example the object hook mechanism\nin the built-in `json` module or subclassing\n`JSONEncoder `.\n\n\nTasks\n=====\n\n``pq`` comes with a higher level ``API`` that helps to manage ``tasks``.\n\n\n.. code-block:: python\n\n from pq.tasks import PQ\n\n pq = PQ(...)\n\n queue = pq['default']\n\n @queue.task(schedule_at='1h')\n def eat(kind):\n print 'umm, %s apples taste good.' % kind\n\n eat('Cox')\n\n queue.work()\n\n\n``tasks``'s ``jobs`` can optionally be re-scheduled on failure:\n\n.. code-block:: python\n\n @queue.task(schedule_at='1h', max_retries=2, retry_in='10s')\n def eat(kind):\n # ...\n\n\nTime expectations can be overriden at ``task`` call:\n\n.. code-block:: python\n\n eat('Cox', _expected_at='2m', _schedule_at='1m')\n\n\nThread-safety\n=============\n\nAll objects are thread-safe as long as a connection pool is provided\nwhere each thread receives its own database connection.\n\n\nChanges\n=======\n\n1.8.1 (2019-07-30)\n------------------\n\n- Added overridable `encode` and `decode` methods which are\n responsible for turning task data into `JSON` and vice-versa.\n\n1.8.0 (2019-07-03)\n------------------\n\n- Change policy on task priority. Tasks with a null-value for\n `expected_at` are now processed after items that have a value set.\n\n1.7.0 (2019-04-07)\n------------------\n\n- Use `SKIP LOCKED` instead of advisory lock mechanism (PostgreSQL 9.5+).\n\n1.6.1 (2018-11-14)\n------------------\n\n- Fix queue class factory pattern.\n\n1.6 (2018-11-12)\n----------------\n\n- Fix compatibility with `NamedTupleCursor`.\n\n- Fix duplicate column name issue.\n\n- Add option to specify own queue class.\n\n\n1.5 (2017-04-18)\n----------------\n\n- Fixed Python 2 compatibility.\n\n\n1.4 (2016-03-25)\n----------------\n\n- Added worker class and handler helper decorator.\n [jeanphix]\n\n\n1.3 (2015-05-11)\n----------------\n\n- Python 3 compatibility.\n [migurski]\n\n- Fix time zone issue.\n\n\n1.2 (2014-10-21)\n----------------\n\nImprovements:\n\n- Fixed concurrency issue where a large number of locks would be held\n as a queue grows in size.\n\n- Fixed a database connection resource issue.\n\n\n1.1 (2014-02-27)\n----------------\n\nFeatures:\n\n- A queue is now also a context manager, providing transactional\n semantics.\n\n- A queues now returns task objects which provide metadata and allows\n reading and writing task data.\n\nImprovements:\n\n- The same connection pool can now be used with different queues.\n\nBugs:\n\n- The `Literal` string wrapper did not work correctly with `psycopg2`.\n\n- The transaction manager now correctly returns connections to the\n pool.\n\n\n1.0 (2013-11-20)\n----------------\n\n- Initial public release.\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/malthe/pq/", "keywords": "", "license": "BSD", "maintainer": "", "maintainer_email": "", "name": "pq", "package_url": "https://pypi.org/project/pq/", "platform": "any", "project_url": "https://pypi.org/project/pq/", "project_urls": { "Homepage": "https://github.com/malthe/pq/" }, "release_url": "https://pypi.org/project/pq/1.8.1/", "requires_dist": null, "requires_python": "", "summary": "PQ is a transactional queue for PostgreSQL.", "version": "1.8.1" }, "last_serial": 5607291, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "6a8d8ed7698ec842939ddce4c5f3968a", "sha256": "e2fa2ba2069f08aeb658f9edf2fbe042ad8549a5bb29d8ff1cfc3108d80b16fc" }, "downloads": -1, "filename": "pq-1.0.tar.gz", "has_sig": false, "md5_digest": "6a8d8ed7698ec842939ddce4c5f3968a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11588, "upload_time": "2013-11-20T19:29:06", "url": "https://files.pythonhosted.org/packages/a5/ae/84a2d4c67f7714105758e031f2e69b682a31cb6af5972f8bfa9941a8f09d/pq-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "2ee2b7513243925a1cc9de565f126117", "sha256": "85ac19b0769b558c3fabb96e62912b31813ca347d143260f18fc55276f80b117" }, "downloads": -1, "filename": "pq-1.1.tar.gz", "has_sig": false, "md5_digest": "2ee2b7513243925a1cc9de565f126117", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13942, "upload_time": "2014-02-27T12:50:41", "url": "https://files.pythonhosted.org/packages/10/0b/3b70924fcc0b662f3affebec4cc5cc58cea4b29d6c09e95223509d1eff64/pq-1.1.tar.gz" } ], "1.1-dev": [], "1.2": [ { "comment_text": "", "digests": { "md5": "f0d16097476f13ded90459ebe5fd52d9", "sha256": "f4e82da2b38a78a0012d7b092764a313ee7fc7973b0612da6a03b4f90a7a676a" }, "downloads": -1, "filename": "pq-1.2.tar.gz", "has_sig": false, "md5_digest": "f0d16097476f13ded90459ebe5fd52d9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14665, "upload_time": "2014-10-21T17:56:58", "url": "https://files.pythonhosted.org/packages/10/3f/88ad0a84e3f87e571818b5a25bba07fd57d3d02ece00feab4eab143f3261/pq-1.2.tar.gz" } ], "1.3": [ { "comment_text": "", "digests": { "md5": "298b55aded5a3c49ba61cd884209964c", "sha256": "c1d62feeff6ab9c362eb2aaeaf1d5062b4c0992eb2507d0852a17398017e85a3" }, "downloads": -1, "filename": "pq-1.3.tar.gz", "has_sig": false, "md5_digest": "298b55aded5a3c49ba61cd884209964c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12271, "upload_time": "2015-05-11T07:43:50", "url": "https://files.pythonhosted.org/packages/5f/bb/4cb8c63851d3e9d0b455912f1c360688719e66978f5fee9cee22e1176e29/pq-1.3.tar.gz" } ], "1.3-dev": [], "1.4": [ { "comment_text": "", "digests": { "md5": "5207ffc528b09b48b858351fe6c651d4", "sha256": "a70f5a16516a1453d2f9fc676f3c55988a054811d86711e0835d9e6298c01e79" }, "downloads": -1, "filename": "pq-1.4.tar.gz", "has_sig": false, "md5_digest": "5207ffc528b09b48b858351fe6c651d4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14022, "upload_time": "2016-03-25T13:41:24", "url": "https://files.pythonhosted.org/packages/d4/02/d4703b44ca3846bd90f4ec200ab6b610223729e3555bb01b621281bb765a/pq-1.4.tar.gz" } ], "1.5": [ { "comment_text": "", "digests": { "md5": "26eecab858834e9fac9c6aa4daf3aff1", "sha256": "e6c39bfd1dee69585f75255976c62d7d52d9f2f342e0d689808250f115422f07" }, "downloads": -1, "filename": "pq-1.5.tar.gz", "has_sig": false, "md5_digest": "26eecab858834e9fac9c6aa4daf3aff1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14525, "upload_time": "2017-04-18T10:29:39", "url": "https://files.pythonhosted.org/packages/ad/db/a837db5872f9a00e3bd7331de03067ba8c57485847874ac1f55790bac005/pq-1.5.tar.gz" } ], "1.6": [ { "comment_text": "", "digests": { "md5": "ba6ff5ee17f0c3bb441ebd09d07e8c0e", "sha256": "07ec795d72bf40d297c53a6d6ae9104e103e70ca0a653d789c828ee36f31722f" }, "downloads": -1, "filename": "pq-1.6.tar.gz", "has_sig": false, "md5_digest": "ba6ff5ee17f0c3bb441ebd09d07e8c0e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17734, "upload_time": "2018-11-12T18:34:58", "url": "https://files.pythonhosted.org/packages/98/7a/9b69f825179803b73159c19cba4c0974adc3c5d244cb2fd9ec4abc6b87ce/pq-1.6.tar.gz" } ], "1.6.1": [ { "comment_text": "", "digests": { "md5": "da3f1348d9d007111410fff1553e943a", "sha256": "16f233d9cf0b01f183852bd95168c7e847b9030bba885c031c013095c1dcf3d1" }, "downloads": -1, "filename": "pq-1.6.1.tar.gz", "has_sig": false, "md5_digest": "da3f1348d9d007111410fff1553e943a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17810, "upload_time": "2018-11-14T17:00:12", "url": "https://files.pythonhosted.org/packages/10/22/498c70afbd3555f0ae9c1171dfaae432eebe78cd456a772efcd6345a7116/pq-1.6.1.tar.gz" } ], "1.7.0": [ { "comment_text": "", "digests": { "md5": "bc8987652dc11e4cf26a03d15b7c0207", "sha256": "680f37bfb22a60d212fa7e0f3939d7e4e31b81cbb97735845b962ae497243463" }, "downloads": -1, "filename": "pq-1.7.0.tar.gz", "has_sig": false, "md5_digest": "bc8987652dc11e4cf26a03d15b7c0207", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17961, "upload_time": "2019-04-07T19:25:37", "url": "https://files.pythonhosted.org/packages/97/12/d06473b2dc24d228414f14b7da272bb1619e9d6881663e2782adf72751cb/pq-1.7.0.tar.gz" } ], "1.8.0": [ { "comment_text": "", "digests": { "md5": "f2a77529e03fe95c06794a111e705754", "sha256": "b17bcbe16e07c18d2a8e1b8fe06b70356f8c78a60bf22d25cfd175e88b9bd50e" }, "downloads": -1, "filename": "pq-1.8.0.tar.gz", "has_sig": false, "md5_digest": "f2a77529e03fe95c06794a111e705754", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18196, "upload_time": "2019-07-03T07:25:38", "url": "https://files.pythonhosted.org/packages/7d/25/43454f5ce3aa72fe20c457009c620862f6337802e3c1c64df9902531378d/pq-1.8.0.tar.gz" } ], "1.8.1": [ { "comment_text": "", "digests": { "md5": "b9224c435b8259442b1a1bb4072b794e", "sha256": "9e2c0195488263902ebc9da8df6c82bebe4ee32c79d9ecd0cdc2945afbf7ad32" }, "downloads": -1, "filename": "pq-1.8.1.tar.gz", "has_sig": false, "md5_digest": "b9224c435b8259442b1a1bb4072b794e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19039, "upload_time": "2019-07-30T11:55:18", "url": "https://files.pythonhosted.org/packages/2b/c9/e74e35501669011133fa4d4fb6df9a0656908526c53d91172392eb27ace7/pq-1.8.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b9224c435b8259442b1a1bb4072b794e", "sha256": "9e2c0195488263902ebc9da8df6c82bebe4ee32c79d9ecd0cdc2945afbf7ad32" }, "downloads": -1, "filename": "pq-1.8.1.tar.gz", "has_sig": false, "md5_digest": "b9224c435b8259442b1a1bb4072b794e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 19039, "upload_time": "2019-07-30T11:55:18", "url": "https://files.pythonhosted.org/packages/2b/c9/e74e35501669011133fa4d4fb6df9a0656908526c53d91172392eb27ace7/pq-1.8.1.tar.gz" } ] }