Browse Source

Finalizing Event Dispatcher Chain & Basic Documentation

almahmoud 7 years ago
parent
commit
5c5ba8d927
3 changed files with 117 additions and 12 deletions
  1. 3 2
      cloudbridge/cloud/base/provider.py
  2. 9 10
      cloudbridge/cloud/base/services.py
  3. 105 0
      docs/topics/event_system.rst

+ 3 - 2
cloudbridge/cloud/base/provider.py

@@ -166,10 +166,9 @@ class EventDispatcher(object):
 
 
 class EventHandler(object):
-    def __init__(self, handler_type, callback, result_callback=None):
+    def __init__(self, handler_type, callback):
         self.handler_type = handler_type
         self.callback = callback
-        self.result_callback = result_callback
         self._next_handler = None
 
     @property
@@ -198,6 +197,8 @@ class EventHandler(object):
                 new_result = next.invoke(args)
                 if new_result:
                     result = new_result
+
+        self.next_handler = None
         return result
 
 

+ 9 - 10
cloudbridge/cloud/base/services.py

@@ -122,9 +122,8 @@ class BaseBucketService(
         def _get_post_log(callback_result, bucket_id):
             log.debug("Returned bucket object: {}".format(callback_result))
 
-        self.provider.events.subscribe(event_name, 20000,
-                                       _get_pre_log)
-        self.provider.events.subscribe(event_name, 21000,
+        self.provider.events.subscribe(event_name, 20000, _get_pre_log)
+        self.provider.events.subscribe(event_name, 30000,
                                        _get_post_log,
                                        result_callback=True)
         self.provider.events.mark_initialized(event_name)
@@ -138,7 +137,7 @@ class BaseBucketService(
         if not self.provider.events.check_initialized(event_name):
             self._init_get()
         return self.provider.events.interceptable_call(event_name,
-                                                       priority=20500,
+                                                       priority=25000,
                                                        callback=self._get,
                                                        bucket_id=bucket_id)
 
@@ -154,7 +153,7 @@ class BaseBucketService(
 
         self.provider.events.subscribe(event_name, 20000,
                                        _find_pre_log)
-        self.provider.events.subscribe(event_name, 21000,
+        self.provider.events.subscribe(event_name, 30000,
                                        _find_post_log,
                                        result_callback=True)
         self.provider.events.mark_initialized(event_name)
@@ -183,7 +182,7 @@ class BaseBucketService(
         if not self.provider.events.check_initialized(event_name):
             self._init_find()
         return self.provider.events.interceptable_call(event_name,
-                                                       priority=20500,
+                                                       priority=25000,
                                                        callback=self._find,
                                                        **kwargs)
 
@@ -203,7 +202,7 @@ class BaseBucketService(
 
         self.provider.events.subscribe(event_name, 20000,
                                        _list_pre_log)
-        self.provider.events.subscribe(event_name, 21000,
+        self.provider.events.subscribe(event_name, 30000,
                                        _list_post_log,
                                        result_callback=True)
         self.provider.events.mark_initialized(event_name)
@@ -216,7 +215,7 @@ class BaseBucketService(
         if not self.provider.events.check_initialized(event_name):
             self._init_list()
         return self.provider.events.interceptable_call(event_name,
-                                                       priority=20500,
+                                                       priority=25000,
                                                        callback=self._list,
                                                        limit=limit,
                                                        marker=marker)
@@ -236,7 +235,7 @@ class BaseBucketService(
 
         self.provider.events.subscribe(event_name, 20000,
                                        _create_pre_log)
-        self.provider.events.subscribe(event_name, 21000,
+        self.provider.events.subscribe(event_name, 30000,
                                        _create_post_log,
                                        result_callback=True)
         self.provider.events.mark_initialized(event_name)
@@ -251,7 +250,7 @@ class BaseBucketService(
         BaseBucket.assert_valid_resource_name(name)
         location = location or self.provider.region_name
         return self.provider.events.interceptable_call(event_name,
-                                                       priority=20500,
+                                                       priority=25000,
                                                        callback=self._create,
                                                        name=name,
                                                        location=location)

+ 105 - 0
docs/topics/event_system.rst

@@ -0,0 +1,105 @@
+Working with the CloudBridge Event System
+=========================================
+In order to provide more comprehensive logging and standardize CloudBridge
+function, we have adopted an Event Dispatcher middleware layer. In short,
+each event has a corresponding list of dispatchers called in priority order.
+For the time being, only a listening subscription model is implemented, thus
+each event has a series of subscribed methods accepting the same parameters,
+that get run in priority order along the main function call.
+This Event System allows both developers and users to easily add
+intermediary functions by event name, without having to modify the
+pre-existing code, thus improving the library's flexibility.
+
+Event Handler
+-------------
+Each function attached to an event has a corresponding handler. This handler
+has a type, a callback function, and a link to the next handler. When
+invoked, the handler will call its callback function and, when available,
+invoke the next handler in the linked list of handlers.
+
+Handler Types
+-------------
+Each Event Handler has a type, which determines how it's invoked. There are
+currently two supported types: `SUBSCRIPTION, and RESULT_SUBSCRIPTION.
+Handlers of SUBSCRIPTION type are simple listeners, who intercept the main
+function arguments but do not modify them. They are independent of any
+previous or future handler, and have no return value. Their associated
+callback function expects the exact same parameters as the main function.
+Handlers of RESULT_SUBSCRIPTION type are similar to SUBSCRIPTION handlers,
+but have access to the last non-null return value from any previous handler.
+They are similarly listeners, intercepting arguments without modifying them
+and do not return any value. Their associated callback will however be
+called with an additional keyword parameter named 'callback_result' holding
+the last non-null return value from any previous handler. The callback
+function thus needs to accept such a parameter.
+
+Event Dispatcher
+----------------
+A single event dispatcher is initialized with the provider, and will hold
+the entirety of the handlers for all events. This dispatcher handles new
+subscriptions and event calls. When an event is called, the dispatcher will
+link each handler to the next one in line, then invoke the first handler,
+thus triggering the chain of handlers.
+
+Priorities
+----------
+As previously mentioned, dispatchers will be invoked in order of priority.
+These priorities are assigned at subscription time, and must be unique.
+Below are the default priorities used across events:
+
++------------------------+----------+
+| Handler                | Priority |
++------------------------+----------+
+| Pre-Logger             | 20000    |
++------------------------+----------+
+| Main Function Call     | 25000    |
++------------------------+----------+
+| Post-Logger            | 30000    |
++------------------------+----------+
+
+The Pre- and Post- loggers represent universal loggers respectively keeping
+track of the event called and its parameters before the call, and the returned
+value after the call. The main function call represents the core function,
+which is not subscribed permanently, but rather called directly with the event.
+
+Example
+-------
+
+Below is an example of the way in which the Event System works for a simple
+getter.
+
+.. code-block:: python
+
+    def _get(object_id):
+        # get the object
+        return obj
+
+    def _pre_log(object_id):
+        print("I am calling 'get' with object_id: {}".format(object_id))
+
+    def _post_log(callback_result, object_id):
+        print("Returned object {} for a 'get' request with object_id: {}"
+        .format(callback_result, object_id))
+
+    event_name = "service.get"
+
+    provider.events.subscribe(event_name, priority=20000, callback=_pre_log)
+    provider.events.subscribe(event_name, priority=30000, callback=_post_log)
+
+    # Public get function
+    def get(object_id):
+        provider.events.interceptable_call(event_name, priority=25000,
+                                           callback=_get,
+                                           object_id=object_id)
+
+In the above example, calling the public `get` function will be the
+equivalent of calling the below function:
+
+.. code-block:: python
+
+    def get(object_id):
+        _pre_log(object_id)
+        result = _get(object_id)
+        _post_log(callback_result=result, object_id)
+        return result
+