{ "info": { "author": "Alessandro Molina", "author_email": "alessandro.molina@axant.it", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Framework :: TurboGears", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "About AsyncJob\n-------------------------\n\n.. image:: https://drone.io/bitbucket.org/axant/tgext.asyncjob/status.png\n :target: https://drone.io/bitbucket.org/axant/tgext.asyncjob\n\nAsyncJob is a TurboGears2 extension made to handle background/synchronous jobs.\nPermits to quickly return responses to the user while the system performs more work on\nbackground, it can be useful for video transcoding, thumbnails generation or other\ntasks where the user cannot expect the require time before getting an answer.\n\nTo perform a task in background simply perform::\n\n from tgext.asyncjob import asyncjob_perform\n asyncjob_perform(callable, arg1, arg2, kwarg=value)\n\nInstalling\n-------------------------------\n\ntgext.asyncjob can be installed both from pypi or from bitbucket::\n\n easy_install tgext.asyncjob\n\nshould just work for most of the users\n\nEnabling AsyncJob\n----------------------------------\n\nIn your application *config/app_cfg.py* append the following lines::\n\n import tgext.asyncjob\n tgext.asyncjob.plugme(base_config)\n\nOr use the pluggable application interface if tgext.pluggable is available::\n\n from tgext.pluggable import plug\n plug(base_config, 'tgext.asyncjob')\n\nYou can pass the **Globals** object itself to the *plug* function::\n\n plug(base_config, 'tgext.asyncjob', app_globals=app_globals)\n\nwhich will be used to store the tasks queue, otherwise asyncjob will autodetect\nthe Globals object from the call stack frame getting the object inside where\nit has been called.\n\nPerforming background tasks\n----------------------------\n\nTo perform a background task you can simply use **tgext.asyncjob.asyncjob_perform**\nit called from any context where there is a valid request it will perform the callable\npassed as first argument in background with the parameters provided::\n\n from tgext.asyncjob import asyncjob_perform\n\n def background_task(number):\n print number*2\n\n asyncjob_perform(background_task, 5)\n\nTracking Tasks Progress\n----------------------------\n\nasyncjob traces tasks status and permits to update it to implement progress bars or other kind\nof user reporting of long running operations. Each time you call **asyncjob_perform** it will\nreturn an unique id for the action you just scheduled that can be used to retrieve\nthe task status anytime.\n\nYou can update progress status anytime from inside the background task itself by calling\n**asyncjob_set_progress(value, data)** the *value* argument is expected to be an int value\nwhile the second optional *data* argument can be anything that you might want to get back later.\n\nTo retrieve the progress status you can call **asyncjob_get_progress** passing it the\nid of the task for which you want to fetch status. Returned value is a 2 items tuple\nwith the first entry being a the numeric value and the second one being the data you passed\nto **asyncjob_set_progress**. \nIf the task has completed it will return *None*, if it has not yet started you will get *(-1, None)*\n\nProgress tracking example::\n\n from tgext.asyncjob import asyncjob_perform, asyncjob_get_progress, asyncjob_set_progress\n\n @expose()\n def controller_method(self):\n def async_action():\n for i in range(5):\n asyncjob_set_progress(i)\n time.sleep(1)\n\n taskid = asyncjob_perform(async_action)\n return redirect(url('/state', uid=taskid))\n\n @expose()\n def state(self, uid):\n state = asyncjob_get_progress(uid)\n if not state:\n return 'Job Completed'\n elif state[0] < 0:\n return 'Not yet started'\n else:\n return str(state[0])\n\nProgress Tracking with Multiple Processes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen using multiple processes to serve your web application, the default task tracking\nsystem won't be able to track the process state between different processes.\n\nTo solve this issue you must rely on an alternative progress tracker that stores the\nstate in a shared storage. By default the ``tgext.asyncjob.tracker.redisdb.RedisProgressTracker``\nis provided, which stores state in a Redis database.\n\nUsing it is as simple as::\n\n from tgext.asyncjob import start_async_worker\n tgext.asyncjob.tracker.redisdb import RedisProgressTracker\n\n class Globals(object):\n def __init__(self):\n start_async_worker(progress_tacker=RedisProgressTracker(host='localhost'))\n\nThe ``RedisProgressTracker`` class accepts ``host``, ``port``, ``db`` and ``timeout`` arguments\nwhich set the database connection options and the timeout of progress tracking keys (to avoid\nleaving stray keys behind). By default db **15** with a timeout of **1 hour** is used.\n\nCustom Progress Trackers\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWriting a custom progress tracker is as simple as providing a class with following methods::\n\n class MyProgressTracker(object):\n def track(self, entryid): pass\n def remove(self, entryid): pass\n def set_progress(self, entryid, value, message): pass\n def get_progress(self, entryid): pass\n\nYour custom progress tracker can then be passed as argument to ``start_async_worker`` to store\nstatus on SQL database, MongoDB or any other system.\n\nRefer to ``tgext.asyncjob.tracker.redisdb.RedisProgressTracker`` or\n``tgext.asyncjob.tracker.memory.MemoryProgressTracker`` for implementation examples.\n\nAccessing the database\n------------------------\n\nBy default asyncjob manages SQLAlchemy sessions and transactions by itself. Each background task\nis encapsulated in a transaction which is reverted in case of any exception.\n\nAsyncJob uses its own SQLAlchemy session, so never pass an object already bound to another session.\nQuery them again.\n\nThe only issue that developers might have to keep in mind is that when looking for objects\nthat they just created before starting the background task, they might not yet be available inside\nthe DB. To avoid this issue asyncjob provides **asyncjob_timed_query** which will perform a query\nlooking for a result until the result itself is found or a timeout is reached (by default 60 seconds).\n\nThis can be used to fetch back objects created before starting the background task waiting for\nthem to appear on the database::\n\n from tgext.asyncjob import asyncjob_perform, asyncjob_timed_query\n\n @expose()\n def controller_method(self):\n def async_query_action(group_id):\n group = asyncjob_timed_query(DBSession.query(Group).filter_by(group_id=group_id)).first()\n group.display_name = 'Prova'\n\n g = Group(group_name='test_group')\n DBSession.add(g)\n DBSession.flush()\n asyncjob_perform(async_query_action, g.group_id)\n return 'OK'\n\nTo change the timeout you can simply pass different *retries* and *interval* parameters to\nasyncjob_timed_query::\n\n asyncjob_timed_query(DBSession.query(Group).filter_by(group_id=group_id),\n retries=10, interval=6).first()", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://bitbucket.org/axant/tgext.asyncjob", "keywords": "turbogears2.extension pylons", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "tgext.asyncjob", "package_url": "https://pypi.org/project/tgext.asyncjob/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/tgext.asyncjob/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://bitbucket.org/axant/tgext.asyncjob" }, "release_url": "https://pypi.org/project/tgext.asyncjob/0.3.1/", "requires_dist": null, "requires_python": null, "summary": "Asynchronous jobs worker for TurboGears2", "version": "0.3.1" }, "last_serial": 5486072, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "a4ef55a56bde63bd9410d10fe813340d", "sha256": "cde21daa619d18ad7f44f34c8a4a0d8ba39ab56116e8d2234acf97986b1ffbd7" }, "downloads": -1, "filename": "tgext.asyncjob-0.1.tar.gz", "has_sig": false, "md5_digest": "a4ef55a56bde63bd9410d10fe813340d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 3747, "upload_time": "2011-05-01T00:30:38", "url": "https://files.pythonhosted.org/packages/c6/38/7d144ddb99e85be711ea9d07996668d52a518659128dad7ab006fc8c3cd6/tgext.asyncjob-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "4bd2b161e471cd52bbd0cef088b4ab46", "sha256": "45a6b000bcfd2c2f3f298dea56d0859df1ac8c14d649416e6cd654e4a12cbbb2" }, "downloads": -1, "filename": "tgext.asyncjob-0.2.tar.gz", "has_sig": false, "md5_digest": "4bd2b161e471cd52bbd0cef088b4ab46", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4823, "upload_time": "2011-05-03T22:48:09", "url": "https://files.pythonhosted.org/packages/d4/6b/4e0a0d326ecb09cc5bd1a477ef92a721476356a2fbdd0ad509cece2b8448/tgext.asyncjob-0.2.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "21428bdc012a9b1e84db97f04b6d9cec", "sha256": "0aecc5aa86f556f531fbe4b156f7bc84181f79bdd473e7312c1520edac900511" }, "downloads": -1, "filename": "tgext.asyncjob-0.2.1.tar.gz", "has_sig": false, "md5_digest": "21428bdc012a9b1e84db97f04b6d9cec", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4835, "upload_time": "2011-06-09T15:21:14", "url": "https://files.pythonhosted.org/packages/e6/93/4b2b3f784fe455a775d5540d86d567989d245399bc438986ad2b81c5bbec/tgext.asyncjob-0.2.1.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "bf3741fc640cc783d8ba6217ef4f901c", "sha256": "9b4b944279a121d0c1c27ac0809d3c17d923b8752d96d4dea1e2765eae2a0bcf" }, "downloads": -1, "filename": "tgext.asyncjob-0.3.0.tar.gz", "has_sig": false, "md5_digest": "bf3741fc640cc783d8ba6217ef4f901c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7498, "upload_time": "2014-04-14T13:05:06", "url": "https://files.pythonhosted.org/packages/42/b2/ffb90bbebbcddf7c71dcf7e545fd748a9bb739e0e830559ec5cf12b0fcbd/tgext.asyncjob-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "d8a53d1e749b1912d5cd0e59058a2049", "sha256": "fabd146661b7eda15afa9d47fee07ed264cdc5b63a4b1449fcd4485748ad469d" }, "downloads": -1, "filename": "tgext.asyncjob-0.3.1.tar.gz", "has_sig": false, "md5_digest": "d8a53d1e749b1912d5cd0e59058a2049", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9510, "upload_time": "2014-10-31T17:09:07", "url": "https://files.pythonhosted.org/packages/5e/18/29b8c3ac2e41e4535a87614f00cab6c470b9b628dc062a59f3304b5e816f/tgext.asyncjob-0.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d8a53d1e749b1912d5cd0e59058a2049", "sha256": "fabd146661b7eda15afa9d47fee07ed264cdc5b63a4b1449fcd4485748ad469d" }, "downloads": -1, "filename": "tgext.asyncjob-0.3.1.tar.gz", "has_sig": false, "md5_digest": "d8a53d1e749b1912d5cd0e59058a2049", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9510, "upload_time": "2014-10-31T17:09:07", "url": "https://files.pythonhosted.org/packages/5e/18/29b8c3ac2e41e4535a87614f00cab6c470b9b628dc062a59f3304b5e816f/tgext.asyncjob-0.3.1.tar.gz" } ] }