========================================== Extending StoryBoard: Event Worker Plugins ========================================== Overview -------- It is sometimes useful to have a method to react to StoryBoard's API events. This can be done using Event Worker plugins, which recieve a notification whenever a POST, PUT, or DELETE action occurs on the API. The plugin can then decide how to process each event asynchronously so as not to impact the stability of the API. Your workers will be detected by `storyboard-worker-daemon` when it starts, and a number of worker processes will be created. When a daemon finds a message in the Rabbit queue, it passes the message to the handle() function of each worker plugin it has found. Note: In order for event worker plugins to work, your StoryBoard config file will need to contain `enable_notifications = True`. Event Worker Plugin Quickstart ------------------------------ Step 1: Create a new python project using setuptools #################################################### This is left as an exercise to the reader. Don't forget to include storyboard as a requirement. Step 2: Implement your plugin ############################# Add a registered entry point in your plugin's `setup.cfg`. The name should be reasonably unique:: [entry_points] storyboard.plugin.worker = my-worker-plugin = my.namespace.plugin:MyEventWorker Then, implement your plugin by extending `WorkerTaskBase`. You may register your own configuration groups, please see `oslo.config `_ for more details.:: from storyboard.plugin.event_worker import WorkerTaskBase class MyEventWorker(WorkerTaskBase): def enabled(self): '''This method should return whether the plugin is enabled and configured. It has access to self.config, which is a reference to storyboard's global configuration object. ''' return True def handle(self, session, author, method, path, status, resource, resource_id, sub_resource=None, sub_resource_id=None, resource_before=None, resource_after=None): """This method takes information about an API event and does something with it, for example creating a SubscriptionEvent in the database for everyone subscribed to the affected resource. :param session: An event-specific SQLAlchemy session. :param author: The author's user record. :param method: The HTTP Method. :param path: The full HTTP Path requested. :param status: The returned HTTP Status of the response. :param resource: The resource type. :param resource_id: The ID of the resource. :param sub_resource: The subresource type. :param sub_resource_id: The ID of the subresource. :param resource_before: The resource state before this event occurred. :param resource_after: The resource state after this event occurred. """ if resource == 'timeline_event': event = db_api.entity_get(models.TimeLineEvent, resource_id, session=session) subscribers = sub_api.subscription_get_all_subscriber_ids( 'story', event.story_id, session=session) for user_id in subscribers: event_info = event.event_info db_api.entity_create(models.SubscriptionEvents, { "author_id": author.id, "subscriber_id": user_id, "event_type": event.event_type, "event_info": event_info }, session=session) Step 3: Install your plugin ########################### Finally, install your plugin, which may require you switch into storyboard's virtual environment. Pip should automatically register your plugin:: pip install my-storyboard-plugin