plone.app.async

HomePage: http://plone.org/products/plone.app.async

Author: Plone Foundation

Download: https://pypi.python.org/packages/source/p/plone.app.async/plone.app.async-1.6.zip

        ===============
plone.app.async
===============

Introduction
============
Integration package for `zc.async`_ allowing asynchronous operations in
Plone 3 and 4.

.. contents::

Repository
=================
- https://github.com/plone/plone.app.async

Installation
============
You will typically run ``plone.app.async`` in a ZEO environment, where you
will have one or more *worker* instances carrying out jobs queued by your
main zope instances.

For the sake of simplicity it is assumed that you have one instance that can
queue new jobs, and one worker instance that consumes them, both operating on
a single database. In this case your buildout configuration will look similar
to the following::

  [zeo]
  recipe = plone.recipe.zope2zeoserver
  file-storage = ${buildout:directory}/var/filestorage/Data.fs

  [instance]
  recipe = plone.recipe.zope2instance
  eggs = Plone plone.app.async
  zcml =
  zcml-additional =
      <include package="plone.app.async" file="single_db_instance.zcml" />
  environment-vars =
      ZC_ASYNC_UUID ${buildout:directory}/var/instance-uuid.txt

  [worker]
  recipe = plone.recipe.zope2instance
  eggs = ${instance:eggs}
  zcml = ${instance:zcml}
  zcml-additional =
      <include package="plone.app.async" file="single_db_worker.zcml" />
  environment-vars =
      ZC_ASYNC_UUID ${buildout:directory}/var/worker-uuid.txt

There are two important stanzas here:

* Each instance has to set the ``ZC_ASYNC_UUID`` environment variable in order
  to integrate properly with `zc.async`_.

* Each instance loads the ``single_db_instance.zcml`` configuration.
  The worker instance loads the ``single_db_worker.zcml`` configuration
  in order to setup the queue and configure itself as a dispatcher.

For more details please look at the `example buildout configurations`_ included in
the package.

.. _`example buildout configurations`: https://github.com/plone/plone.app.async


Plone 3
-------

Use zope.app.keyreference


Plone 4
-------

Use five.intid


Credits
=======
Code from Enfold's `plone.async.core`_ package has been used for setting up the queues.

References
==========
* `zc.async`_ on PyPI
* `plone.async.core`_ Subversion repository

.. _zc.async: http://pypi.python.org/pypi/zc.async
.. _plone.async.core: https://svn.enfoldsystems.com/public/plone.async.core


User Documentation
==================

Basic use
---------

Assuming your setup is done correctly, you can start by obtaining the
``AsyncService`` utility::

    >>> from zope.component import getUtility
    >>> from plone.app.async.interfaces import IAsyncService
    >>> async = getUtility(IAsyncService)
    >>> async
    <plone.app.async.service.AsyncService object at ...>
    >>> folder = layer['test-folder']
    >>> portal = layer['portal']

You can already get the ``zc.async`` queues::

    >>> async.getQueues()
    <zc.async.queue.Queues object at ...>

    >>> import zc.async.dispatcher
    >>> from plone.app.async.testing import _dispatcher_uuid
    >>> zc.async.dispatcher.get(_dispatcher_uuid)
    <zc.async.dispatcher.Dispatcher object at ...>
    >>> queue = async.getQueues()['']
    >>> queue
    <zc.async.queue.Queue object at ...>

Let's define a simple function to be executed asynchronously. Note that the
first argument **must** be a valid Zope object::

    >>> from plone.app.async.tests.funcs import *

and queue it::

    >>> job = async.queueJob(addNumbers, folder, 40, 2)
    >>> len(queue)
    1
    >>> job.status
    u'pending-status'


In real life the job would be executed by the worker. In the tests we need
to commit in order to let the  dispatcher become aware of the job and
execute it.  Also we wait for the job to complete before continuing with the
test::

    >>> import transaction
    >>> from zc.async.testing import wait_for_result
    >>> transaction.commit()
    >>> wait_for_result(job)
    42

Batches of jobs
----------------

Let's now try some jobs that create persistent objects. First define
the tasks to be executed asynchronously::

    >>> from Products.CMFCore.utils import getToolByName


Queue a job that creates a