-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Adding middleware support in factory #195
base: main
Are you sure you want to change the base?
Conversation
Pull Request Test Coverage Report for Build 1500
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss the details later on today. I think the idea of maintaining similarity to a local event manager when subscribing to factory level events is a good one, we just need to make it behave in a way that's unsurprising. Perhaps the one that's least surprising is to simply share the middleware object. Fundamentally, I guess we have to answer these questions:
a. is factory level middleware different from individual provider level middleware, or should they be interchangeable? That is, is can provider.middleware.add(middleware)
behave the same as factory.middleware.add(middleware)
?
b. How do we avoid middleware internal to providers accidentally subscribing to "global" events. Should we?
c. If the answer is no, how do provider internal events, relate to global external events? How would the chain of handlers work? Would a namespace work?
@@ -83,11 +83,11 @@ def debug_mode(self): | |||
|
|||
|
|||
class BaseCloudProvider(CloudProvider): | |||
def __init__(self, config): | |||
def __init__(self, config, middleware_manager=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great, better than sending in middleware as a list.
cloudbridge/cloud/factory.py
Outdated
super(ParentMiddlewareManager, self).__init__(event_manager) | ||
self.middleware_constructors = [] | ||
|
||
def add_constructor(self, middleware_class, *args): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could possibly be renamed to add_middleware_class, accepting the class in question, and both the constructor args and kwargs.
cloudbridge/cloud/factory.py
Outdated
new_handler = handler.__class__(handler.event_pattern, | ||
handler.priority, | ||
handler.callback) | ||
new_manager.events.subscribe(new_handler) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this means that events added to the factory later won't be subscribed to previously created providers? This is ok, but I think we need to clarify how exactly factory event subscriptions are meant to work and what the intended use cases are, so we know for sure that this is the correct behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was the original question that I had about this: whether we should make the provider object independent after it was created, or always treat it as a "child" of the factory. If the latter, it's definitely doable, but I would then suggest making the factory accessible through the provider as well.
cloudbridge/cloud/factory.py
Outdated
def get_subscribed_handlers(self): | ||
handlers = [] | ||
# Todo: Expose this better in pyeventsystem library | ||
event_dict = self.events._SimpleEventDispatcher__events |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why we can't just access self.events?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.events
is the SimpleEventDispatcher
, which currently doesn't have a property exposing the events dict. We definitely should add the property, but I was avoiding changing the other library for the time being, before we discuss this further.
cloudbridge/cloud/factory.py
Outdated
@@ -27,9 +79,14 @@ class CloudProviderFactory(object): | |||
""" | |||
|
|||
def __init__(self): | |||
self._middleware = ParentMiddlewareManager() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need a different name because ParentMiddlewareManager doesn't seem to explain what it's doing. Also, there is the issue of namespacing. And finally, I guess there's the issue of being able to intercept behaviour of a particular cloud (say openstack), and change behaviour for all classes of that cloud. One way would be to prefix the cloudname to the event. Another way would be is to check the instancetype of the sender: if isinstance(OpenStackProvider, event_args['sender'].provider)
or some such thing. I think namespacing would be good as long as isolation is maintained.
# Removing install step from add. Since this manager is meant to create | ||
# other managers rather than run. This will also simplify separating | ||
# handlers added through middleware from those subscribed directly | ||
def add(self, middleware): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should provide dual semantics here - one for shared middleware objects, and another for independent middleware, just to keep it simple. I'm currently leaning in favour of the factory namespacing child event dispatchers, and forwarding them as necessary, so that we still maintain event isolation within a given provider. I think we probably just need to avoid a scenario where providers are unwittingly subscribing to events outside of the provider.
Codecov Report
@@ Coverage Diff @@
## master #195 +/- ##
==========================================
- Coverage 88.03% 87.96% -0.08%
==========================================
Files 36 36
Lines 7775 7902 +127
Branches 854 868 +14
==========================================
+ Hits 6845 6951 +106
- Misses 594 610 +16
- Partials 336 341 +5
Continue to review full report at Codecov.
|
This adds support for middleware in factory, which then gets inherited by any provider object created by this factory.
Three options to add middleware from factory:
and 3) adding events directly which will recreate a handler with the same callback function (bound methods will remain bound to their object)
For all these scenarios, provider objects will inherit the events from the factory: