Skip to content

Commit

Permalink
Return error exit code from the Core process if the Core session fails
Browse files Browse the repository at this point in the history
  • Loading branch information
kozlovsky committed Aug 29, 2022
1 parent 3bc8593 commit a835472
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/tribler/core/components/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __init__(self, config: TriblerConfig = None, components: List[Component] = (
shutdown_event: Event = None, notifier: Notifier = None, failfast: bool = True):
# deepcode ignore unguarded~next~call: not necessary to catch StopIteration on infinite iterator
self.id = next(Session._next_session_id)
self.exit_code = 0
self.failfast = failfast
self.logger = logging.getLogger(self.__class__.__name__)
self.config: TriblerConfig = config or TriblerConfig()
Expand Down Expand Up @@ -164,6 +165,7 @@ def _reraise_startup_exception_in_separate_task(self):
async def exception_reraiser():
e = self._startup_exception
if isinstance(e, ComponentStartupException) and e.component.tribler_should_stop_on_component_error:
self.exit_code = 1
self.shutdown_event.set()

# the exception should be intercepted by event loop exception handler
Expand Down
23 changes: 19 additions & 4 deletions src/tribler/core/start_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import signal
import sys
from pathlib import Path
from typing import List

from tribler.core import notifications
Expand Down Expand Up @@ -92,7 +93,12 @@ def components_gen(config: TriblerConfig):
yield GigachannelManagerComponent()


async def core_session(config: TriblerConfig, components: List[Component]):
async def core_session(config: TriblerConfig, components: List[Component]) -> int:
"""
Async task for running a new Tribler session.
Returns an exit code, which is non-zero if the Tribler session finished with an error.
"""
session = Session(config, components, failfast=False)
signal.signal(signal.SIGTERM, lambda signum, stack: session.shutdown_event.set)
async with session.start() as session:
Expand All @@ -108,12 +114,16 @@ async def core_session(config: TriblerConfig, components: List[Component]):
session.notifier[notifications.tribler_shutdown_state]("Saving configuration...")
config.write()

return session.exit_code


def run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=False):
def run_tribler_core_session(api_port: str, api_key: str, state_dir: Path, gui_test_mode: bool = False) -> int:
"""
This method will start a new Tribler session.
Note that there is no direct communication between the GUI process and the core: all communication is performed
through the HTTP API.
Returns an exit code value, which is non-zero if the Tribler session finished with an error.
"""
logger.info(f'Start tribler core. API port: "{api_port}". '
f'API key: "{api_key}". State dir: "{state_dir}". '
Expand Down Expand Up @@ -154,7 +164,7 @@ def run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=False):
loop.set_exception_handler(exception_handler.unhandled_error_observer)

try:
loop.run_until_complete(core_session(config, components=list(components_gen(config))))
exit_code = loop.run_until_complete(core_session(config, components=list(components_gen(config))))
finally:
if trace_logger:
trace_logger.close()
Expand All @@ -163,6 +173,8 @@ def run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=False):
for handler in logging.getLogger().handlers:
handler.flush()

return exit_code


def run_core(api_port, api_key, root_state_dir, parsed_args):
logger.info('Running Core' + ' in gui_test_mode' if parsed_args.gui_test_mode else '')
Expand All @@ -171,4 +183,7 @@ def run_core(api_port, api_key, root_state_dir, parsed_args):
with single_tribler_instance(root_state_dir):
version_history = VersionHistory(root_state_dir)
state_dir = version_history.code_version.directory
run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=parsed_args.gui_test_mode)
exit_code = run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=parsed_args.gui_test_mode)

if exit_code:
sys.exit(exit_code)
13 changes: 8 additions & 5 deletions src/tribler/gui/core_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,14 @@ def get_last_core_output(self, quoted=True):
@staticmethod
def format_error_message(exit_code: int, exit_status: int) -> str:
message = f"The Tribler core has unexpectedly finished with exit code {exit_code} and status: {exit_status}."
try:
string_error = os.strerror(exit_code)
except ValueError:
# On platforms where strerror() returns NULL when given an unknown error number, ValueError is raised.
string_error = 'unknown error number'
if exit_code == 1:
string_error = "Application error"
else:
try:
string_error = os.strerror(exit_code)
except ValueError:
# On platforms where strerror() returns NULL when given an unknown error number, ValueError is raised.
string_error = 'unknown error number'
message += f'\n\nError message: {string_error}'
return message

Expand Down

0 comments on commit a835472

Please sign in to comment.