2021-09-09 service_instance performance#
TLDR; service_instance is unlikely to be cached for the foreseeable future.
In order to operate against vCenter, we need to have a connection to it. That
is handled via the
All external functions operating against vcenter accept a
This is useful for testing. It also allows a user to operate against multiple
service instances at once.
The default value is
None, which triggers the creation of a new service
This is slow.
For performance, a user could reuse a handle to a service instance.
Pushing this on the user is bad.
How could we handle this for the user?
We have tried decorators to inject the
service_instance if it wasn’t
passed explicitly, the salt loader didn’t like that (I don’t know the
full details). This would slightly simplify the code, but wouldn’t directly
help the user; we’d still need a singleton or cache.
Assuming that the
service_instance manages its connection well and reconnects
when necessary, we could cache it or make it a singleton, something like this:
def load_service_instance(): return get_service_instance(opts=__opts__, pillar=__pillar__) SI = lazy_object_proxy.Proxy(load_service_instance) def foo(service_instance=SI): pass
The Salt Loader#
A potential problem is the salt loader and memory leaks. Basically, modules can
be reloaded by salt - the file is read again, then replaces the current module
Modules are not designed to be replaced like that and it’s easy for this to trigger memory leaks. We do not fully understand the conditions that cause these leaks.
If we were to do this, we would need to implement the code, then stress test it,
then inspect all of the memory via
gc.get_objects() to ensure that only one
service instance exists. As part of that we’d also need to make sure that only
one service instance class exists.
This is because
isinstance don’t work as you might expect when
dealing with modules that are reloaded - you end up with multiple class instances
that are identical except for their
id (which is used to calculate class equality).
A Smarter Instance#
If the service instance connection isn’t managed well we would need a smarter
object than the mentioned
lazy_object_proxy, we would need to auto-reconnect
on certain exceptions.
class ReconnectProxy(lazy_object_proxy.Proxy): def __getattr__(self, item): try: return super().__getattr__(item) except ConnectionError: self._proxied_obj = load_service_instance(opts=__opts__, pillar=__pillar__) return super().__getattr__(item)
This is all doable, but is not a priority.