add daemon Component and ComponentManager classes

This commit is contained in:
Jack Robison 2018-04-02 15:11:27 -04:00
parent cab8416596
commit 68b31a09b4
No known key found for this signature in database
GPG key ID: DF25C68FE0239BB2
3 changed files with 152 additions and 0 deletions

View file

@ -0,0 +1,57 @@
import logging
from twisted.internet import defer
from ComponentManager import ComponentManager
log = logging.getLogger(__name__)
class ComponentType(type):
def __new__(mcs, name, bases, newattrs):
klass = type.__new__(mcs, name, bases, newattrs)
if name != "Component":
ComponentManager.components.add(klass)
return klass
class Component(object):
"""
lbrynet-daemon component helper
Inheriting classes will be automatically registered with the ComponentManager and must implement setup and stop
methods
"""
__metaclass__ = ComponentType
depends_on = []
component_name = None
running = False
@classmethod
def setup(cls):
raise NotImplementedError() # override
@classmethod
def stop(cls):
raise NotImplementedError() # override
@classmethod
@defer.inlineCallbacks
def _setup(cls):
try:
result = yield defer.maybeDeferred(cls.setup)
cls.running = True
defer.returnValue(result)
except Exception as err:
log.exception("Error setting up %s", cls.component_name or cls.__name__)
raise err
@classmethod
@defer.inlineCallbacks
def _stop(cls):
try:
result = yield defer.maybeDeferred(cls.stop)
cls.running = False
defer.returnValue(result)
except Exception as err:
log.exception("Error stopping %s", cls.__name__)
raise err

View file

@ -0,0 +1,93 @@
import logging
from twisted.internet import defer
log = logging.getLogger(__name__)
class ComponentManager(object):
components = set()
@classmethod
def sort_components(cls, reverse=False):
"""
Sort components by requirements
"""
steps = []
staged = set()
components = set(cls.components)
# components with no requirements
step = []
for component in set(components):
if not component.depends_on:
step.append(component)
staged.add(component.component_name)
components.remove(component)
if step:
steps.append(step)
while components:
step = []
to_stage = set()
for component in set(components):
reqs_met = 0
for needed in component.depends_on:
if needed in staged:
reqs_met += 1
if reqs_met == len(component.depends_on):
step.append(component)
to_stage.add(component.component_name)
components.remove(component)
if step:
staged.update(to_stage)
steps.append(step)
elif components:
raise SyntaxError("components cannot be started: %s" % components)
if reverse:
steps.reverse()
return steps
@classmethod
@defer.inlineCallbacks
def setup(cls):
"""
Start Components in sequence sorted by requirements
:return: (defer.Deferred)
"""
stages = cls.sort_components()
for stage in stages:
yield defer.DeferredList([component._setup() for component in stage])
@classmethod
@defer.inlineCallbacks
def stop(cls):
"""
Stop Components in reversed startup order
:return: (defer.Deferred)
"""
stages = cls.sort_components(reverse=True)
for stage in stages:
yield defer.DeferredList([component._stop() for component in stage])
@classmethod
def all_components_running(cls, *component_names):
"""
:return: (bool) True if all specified components are running
"""
c = {component.component_name: component for component in cls.components}
for component in component_names:
if component not in c:
raise NameError("%s is not a known Component" % component)
if not c[component].running:
return False
return True
@classmethod
def get_component(cls, component_name):
for component in cls.components:
if component.component_name == component_name:
return component
raise NameError(component_name)

View file

@ -17,6 +17,7 @@ from lbrynet.core.Error import InvalidAuthenticationToken
from lbrynet.core import utils from lbrynet.core import utils
from lbrynet.daemon.auth.util import APIKey, get_auth_message from lbrynet.daemon.auth.util import APIKey, get_auth_message
from lbrynet.daemon.auth.client import LBRY_SECRET from lbrynet.daemon.auth.client import LBRY_SECRET
from lbrynet.daemon.Component import ComponentManager
from lbrynet.undecorated import undecorated from lbrynet.undecorated import undecorated
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -132,6 +133,7 @@ class JSONRPCServerType(type):
class AuthorizedBase(object): class AuthorizedBase(object):
__metaclass__ = JSONRPCServerType __metaclass__ = JSONRPCServerType
component_manager = ComponentManager
@staticmethod @staticmethod
def deprecated(new_command=None): def deprecated(new_command=None):