improve error messages when attached modules fail on startup
Change-Id: Ic1d2d77de2574043749ddbc00def48a6fe77b2bd
This commit is contained in:
@@ -342,6 +342,7 @@ class Module(HasAccessibles):
|
|||||||
self.attachedModules = {}
|
self.attachedModules = {}
|
||||||
self.errors = []
|
self.errors = []
|
||||||
self._isinitialized = False
|
self._isinitialized = False
|
||||||
|
self._initfailed = False
|
||||||
self.updateCallback = srv.dispatcher.announce_update
|
self.updateCallback = srv.dispatcher.announce_update
|
||||||
|
|
||||||
# handle module properties
|
# handle module properties
|
||||||
@@ -612,6 +613,7 @@ class Module(HasAccessibles):
|
|||||||
"""
|
"""
|
||||||
# we do not need self.errors any longer. should we delete it?
|
# we do not need self.errors any longer. should we delete it?
|
||||||
# del self.errors
|
# del self.errors
|
||||||
|
self.polledModules = [m for m in self.polledModules if not m._initfailed]
|
||||||
if self.polledModules:
|
if self.polledModules:
|
||||||
self.__poller = mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
|
self.__poller = mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
|
||||||
self.startModuleDone = True
|
self.startModuleDone = True
|
||||||
@@ -723,28 +725,27 @@ class Module(HasAccessibles):
|
|||||||
rfunc = getattr(mobj, 'read_' + pname)
|
rfunc = getattr(mobj, 'read_' + pname)
|
||||||
if rfunc.poll:
|
if rfunc.poll:
|
||||||
pinfo.polled_parameters.append((mobj, rfunc, pobj))
|
pinfo.polled_parameters.append((mobj, rfunc, pobj))
|
||||||
while True:
|
try:
|
||||||
try:
|
for mobj in list(self.modules):
|
||||||
for mobj in modules:
|
if mobj._initfailed:
|
||||||
# TODO when needed: here we might add a call to a method :meth:`beforeWriteInit`
|
modules.remove(mobj)
|
||||||
mobj.writeInitParams()
|
for mobj in modules:
|
||||||
mobj.initialReads()
|
# TODO when needed: here we might add a call to a method :meth:`beforeWriteInit`
|
||||||
# call all read functions a first time
|
mobj.writeInitParams()
|
||||||
for m in polled_modules:
|
mobj.initialReads()
|
||||||
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
|
# call all read functions a first time
|
||||||
mobj.callPollFunc(rfunc, raise_com_failed=True)
|
for m in polled_modules:
|
||||||
# TODO when needed: here we might add calls to a method :meth:`afterInitPolls`
|
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
|
||||||
break
|
mobj.callPollFunc(rfunc, raise_com_failed=True)
|
||||||
except CommunicationFailedError as e:
|
# TODO when needed: here we might add calls to a method :meth:`afterInitPolls`
|
||||||
# when communication failed, probably all parameters and may be more modules are affected.
|
except CommunicationFailedError as e:
|
||||||
# as this would take a lot of time (summed up timeouts), we do not continue
|
# when communication failed, probably all parameters and may be more modules are affected.
|
||||||
# trying and let the server accept connections, further polls might success later
|
# as this would take a lot of time (summed up timeouts), we do not continue
|
||||||
if started_callback:
|
# trying and let the server accept connections, further polls might success later
|
||||||
self.log.error('communication failure on startup: %s', e)
|
if started_callback:
|
||||||
started_callback()
|
self.log.error('communication failure on startup: %s', e)
|
||||||
started_callback = None
|
started_callback()
|
||||||
self.triggerPoll.wait(0.1) # wait for reconnection or max 10 sec.
|
started_callback = None
|
||||||
break
|
|
||||||
if started_callback:
|
if started_callback:
|
||||||
started_callback()
|
started_callback()
|
||||||
if not polled_modules: # no polls needed - exit thread
|
if not polled_modules: # no polls needed - exit thread
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ from frappy.version import get_version
|
|||||||
from frappy.modules import Module
|
from frappy.modules import Module
|
||||||
|
|
||||||
|
|
||||||
|
class InitFailed(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SecNode:
|
class SecNode:
|
||||||
"""Managing the modules.
|
"""Managing the modules.
|
||||||
|
|
||||||
@@ -85,11 +89,15 @@ class SecNode:
|
|||||||
if not modobj.initModuleDone:
|
if not modobj.initModuleDone:
|
||||||
self.errors.append(f'{modobj.initModule.__qualname__} was not '
|
self.errors.append(f'{modobj.initModule.__qualname__} was not '
|
||||||
f'called, probably missing super call')
|
f'called, probably missing super call')
|
||||||
|
except InitFailed:
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self.traceback_counter == 0:
|
if self.traceback_counter == 0:
|
||||||
self.log.exception(traceback.format_exc())
|
self.log.exception(traceback.format_exc())
|
||||||
self.traceback_counter += 1
|
self.traceback_counter += 1
|
||||||
self.errors.append(f'error initializing {modulename}: {e!r}')
|
self.errors.append(f'error initializing {modulename}: {e!r}')
|
||||||
|
modobj._initfailed = True
|
||||||
|
raise InitFailed('try to access erroneous module')
|
||||||
modobj._isinitialized = True
|
modobj._isinitialized = True
|
||||||
self.log.debug('initialized module %r', modulename)
|
self.log.debug('initialized module %r', modulename)
|
||||||
return modobj
|
return modobj
|
||||||
@@ -101,8 +109,11 @@ class SecNode:
|
|||||||
When creating a new module, srv.module_config is accessed to get the
|
When creating a new module, srv.module_config is accessed to get the
|
||||||
modules configuration.
|
modules configuration.
|
||||||
"""
|
"""
|
||||||
if modulename in self.modules:
|
modobj = self.modules.get(modulename)
|
||||||
return self.modules[modulename]
|
if modobj:
|
||||||
|
if modobj._initfailed:
|
||||||
|
raise InitFailed('try to access erroneous module')
|
||||||
|
return modobj
|
||||||
if modulename in list(self.modules.values()):
|
if modulename in list(self.modules.values()):
|
||||||
# it's actually already the module object
|
# it's actually already the module object
|
||||||
return modulename
|
return modulename
|
||||||
@@ -205,8 +216,11 @@ class SecNode:
|
|||||||
def build_descriptive_data(self):
|
def build_descriptive_data(self):
|
||||||
modules = {}
|
modules = {}
|
||||||
result = {'modules': modules}
|
result = {'modules': modules}
|
||||||
for modulename in self.modules:
|
for modulename in list(self.modules):
|
||||||
modobj = self.get_module(modulename)
|
try:
|
||||||
|
modobj = self.get_module(modulename)
|
||||||
|
except InitFailed:
|
||||||
|
continue
|
||||||
if not modobj.export:
|
if not modobj.export:
|
||||||
continue
|
continue
|
||||||
# some of these need rework !
|
# some of these need rework !
|
||||||
|
|||||||
Reference in New Issue
Block a user