Switch to side-by-side view

--- a/Allura/docs/platform_tour.rst
+++ b/Allura/docs/platform_tour.rst
@@ -10,7 +10,7 @@
 - Indexing and search
 - Authentication and Authorization
 - Email integration (every tool application gets its own email address)
-- Asynchronous processing via RabbitMQ
+- Asynchronous processing with background tasks and events
 - `Markdown <http://daringfireball.net/projects/markdown/>`_ markup formatting
 - Simple autolinking between different artifacts in the forge
 - Attachment handling
@@ -148,76 +148,35 @@
 -----------------------------------------
 
 Much of the actual functionality of Allura comes from code that runs
-*outside* the context of a web request, in the `reactor` server (invoked by
-running `paster reactor development.ini`.  Asynchronous processing is performed
-by two types of functions, *auditors* and *reactors*, differentiated as follows:
-
-Auditor
-    Auditors listen to queues on the `audit` exchange.
-    Messages sent to an auditor queue are interpreted *imperatively* ("do this").
-    Auditor-type messages should specify a project ID `project_id`, an
-    application mount point `mount_point`, and a user ID `user_id`, which will be
-    used by the platform to set the context before calling the registered
-    callback, and all of which reference the *recipient* of the message.  An
-    auditor callback function is called *once* for each message received on its queue.
-Reactor
-    Reactors listen to queues on the `react` exchange.
-    Messages sent to a reactor queue are interpreted in an *advisory* manner
-    ("this was done").  Reactor-type messages should specify a project ID
-    `project_id` and a user ID `user_id`, which will be
-    used by the platform to set the context before calling the registered
-    callback, and all of which reference the *source* of the message.  If the
-    reactor callback is an instance method, it will be called once for each
-    instance of the tool that exists for the given project for each message
-    received on its queue.  If it is a class method, it will be called once for
-    each message received on its queue.  For instance, the Tracker tool may be
-    configured to react to SCM commit messages in order to generate links between
-    SCM commits and Tracker tickets.  *All tracker instances* in a project will
-    be notified of SCM commits in such a case.
-
-In order to create a callback function for an auditor or a reactor, simply add a
-method to the tool application class that is decorated either with the `@audit`
-or the `@react` decorator.  For instance, the discussion tool defines a reactor on
-the `Forum.new_post` message::
-
-    @react('Forum.new_post')
-    def notify_subscribers(self, routing_key, data):
-        ....
-
-If there are a large number of reactors, you can define them in a separate module
-and use the `mixin_reactors()` method as in the SCM tool::
-
-    from .reactors import reactors
-    ...
-    class ForgeGitApp(Application):
-        ...
-    mixin_reactors(ForgeGitApp, reactors)
-
-.. sidebar:: Updating auditors and reactors
-
-   If you add, remove, or change the routing key of any auditor or reactor,
-   chances are that you'll need to re-configure the rabbitmq server to handle the
-   queue changes.  To do this, you need simply to run the following command::
-
-       $ paster reactor_setup development.ini
-
-   This will tear down all the queues and recreate them based on the code that
-   currently exists.
-
-In order to actually *send* a message to either the `audit` or `react` exchange,
-a helper method is provided in the pylons global object `g`:
-
-.. method:: allura.lib.app_globals.AppGlobals.publish(xn, key, message=None, **kw)
-   :noindex:
-
-   Used to send messages to the named exchange.  This method will automatically
-   set the message attributes `project_id`, `mount_point`, and `user_id` based on
-   the current context.
-
-   :param xn: exchange name (either "audit" or "react")
-   :param key: routing key (e.g. "Forum.new_post")
-   :param message: optional dictionary with message content
-   :param kw: optional keyword arguments which are passed through to the `carrot.Publisher`
+*outside* the context of a web request, in the `taskd` server (invoked by
+running `paster taskd development.ini`.  Asynchronous processing is performed
+by two types of functions, *tasks* and *events*, differentiated as follows:
+
+Task
+    Tasks are module-level global functions.  They are annotated with the `@task`
+    decorator and are invoked with the `.post` method.  For instance, to schedule
+    a task  `foobar` to execute in the `taskd` context, you would write::
+
+       @task
+       def foobar(a,b,c=5): ...
+       
+       foobar.post(9,1,c=15)
+
+Event
+    Events are intended for "fan-out" types of events.  Events have a string
+    name, and are  "listened" for by using the `@event_handler` decorator.  The
+    `g.post_event()` helper is provided to run the event handlers for a
+    particular event in the `taskd` context.  Multiple event handlers can be
+    registered for each event::
+
+        @event_handler('event_name')
+        def handler1(topic, *args, **kwargs): ...
+
+        @event_handler('event_name')
+        def handler2(topic, *args, **kwargs): ...
+
+        g.post_event('event_name', 1,2,3, a=5)
+
 
 Email Integration
 -----------------------------------------
@@ -231,8 +190,8 @@
 queried to determine whether the identified user has authority to send an email
 to the given app/topic combination by calling `c.app.has_access(user, topic)`.
 If the user has access, the message is decomposed into its component parts (if a
-multipart MIME-encoded message) and one `audit` message is generated for each
-part with the following fields:
+multipart MIME-encoded message) and `c.app.handle_message(topic, message)` is
+called for each part with the following components to the `msg` dict:
 
 headers
   The actual headers parsed from the body of the message
@@ -253,21 +212,24 @@
   The MIME content_type of the message part
 payload
   The actual content of the message part
-user_id
-  The ID of the user who sent the message
-
-Once the message is generated, it is sent to the `audit` exchange with the
-routing key <Tool Type>.<topic>.  For instance, a message to comment on a Wiki
-page might have the routing key `Wiki.MainPage`.
 
 The Allura platform also provides full support for *sending* email without
 worrying about the specifics of SMTP or sendmail handling.  In order to send an
-email, a tool needs simply to send an `audit` message with the routing key
-`forgemail.send_email` and the following fields:
-
-from
+email, simply post a task for `allura.tasks.mail_tasks.sendmail` with the
+following arguments:
+
+fromaddr
   Return address on the message (usually the topic@tool_name that generated
   it)
+destinations
+  List of email addresses and/or :class:`bson.ObjectId` s for
+  :class:`allura.model.auth.User` objects
+text
+  Markdown-formatted body of the message (If the user has requested html or
+  combined text+html messages in their preferences, the Markdown will be so
+  rendered.  Otherwise a plain text message will be sent.)
+reply_to
+  Address to which replies should be sent
 subject
   Subject of the message
 message_id
@@ -276,10 +238,3 @@
 in_reply_to (optional)
   Value to put in the `In-Reply-To` header (the `parent_id` field of a
   :class:`allura.model.artifact.Message` is suitable for this)
-destinations
-  List of email addresses and/or :class:`bson.ObjectId` s for
-  :class:`allura.model.auth.User` objects
-text
-  Markdown-formatted body of the message (If the user has requested html or
-  combined text+html messages in their preferences, the Markdown will be so
-  rendered.  Otherwise a plain text message will be sent.)