Skip to content

Commit

Permalink
Do not interrupt the whole dispatcher if a single handler fails
Browse files Browse the repository at this point in the history
Catch exceptions from event handlers (and log them), instead of
interrupting the whole event dispatcher. This avoid misterious stopping
processing the events if a single thing goes wrong. Additionally,
logging event details may help debugging the issue.
  • Loading branch information
marmarek committed Sep 28, 2021
1 parent f7ebf96 commit ecf9723
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 1 deletion.
7 changes: 6 additions & 1 deletion qubesadmin/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,9 @@ def handle(self, subject, event, **kwargs):
for h_func in h_func_set
if fnmatch.fnmatch(event, h_name)]
for handler in handlers:
handler(subject, event, **kwargs)
try:
handler(subject, event, **kwargs)
except: # pylint: disable=bare-except
self.app.log.exception(
'Failed to handle event: %s, %s, %s',
subject, event, kwargs)
10 changes: 10 additions & 0 deletions qubesadmin/tests/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ def test_002_handler_glob_partial(self):
self.dispatcher.handle('', 'some-event', arg1='value1')
self.assertFalse(handler.called)

def test_003_handler_error(self):
handler = unittest.mock.Mock()
self.dispatcher.add_handler('some-event', handler)
handler2 = unittest.mock.Mock(side_effect=AssertionError)
self.dispatcher.add_handler('some-event', handler2)
# should catch the exception
self.dispatcher.handle('', 'some-event', arg1='value1')
handler.assert_called_once_with(None, 'some-event', arg1='value1')
handler2.assert_called_once_with(None, 'some-event', arg1='value1')

async def mock_get_events_reader(self, stream, cleanup_func, expected_vm,
vm=None):
self.assertEqual(expected_vm, vm)
Expand Down

0 comments on commit ecf9723

Please sign in to comment.