Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the detection of running processes by including process UID to the check #7637

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/run_tribler_headless.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ async def signal_handler(sig):
current_process = TriblerProcess.current_process(ProcessKind.Core)
self.process_manager = ProcessManager(root_state_dir, current_process)
set_global_process_manager(self.process_manager)
current_process.start_updating_thread()

if not self.process_manager.current_process.become_primary():
msg = 'Another Core process is already running'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import psutil
from ipv8.taskmanager import TaskManager

GUI_UID_ENV_KEY = 'TRIBLER_GUI_UID'
GUI_PID_ENV_KEY = 'TRIBLER_GUI_PID'
CHECK_INTERVAL = 10

Expand Down Expand Up @@ -52,6 +53,16 @@ def get_gui_pid() -> Optional[int]:
logger.warning(f'Cannot parse {GUI_PID_ENV_KEY} environment variable: {pid}')
return None

@staticmethod
def get_gui_uid() -> Optional[int]:
uid = os.environ.get(GUI_UID_ENV_KEY, None)
if uid:
try:
return int(uid)
except ValueError:
logger.warning(f'Cannot parse {GUI_UID_ENV_KEY} environment variable: {uid}')
return None

@classmethod
def get_gui_process(cls) -> Optional[psutil.Process]:
pid = cls.get_gui_pid()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import psutil
import pytest

from tribler.core.components.gui_process_watcher.gui_process_watcher import GUI_PID_ENV_KEY, GuiProcessNotRunning, \
from tribler.core.components.gui_process_watcher.gui_process_watcher import GUI_PID_ENV_KEY, GUI_UID_ENV_KEY, \
GuiProcessNotRunning, \
GuiProcessWatcher


Expand Down Expand Up @@ -33,6 +34,19 @@ def test_get_gui_pid(caplog):
assert GuiProcessWatcher.get_gui_pid() == 123


def test_get_gui_uid(caplog):
with patch.dict(os.environ, {GUI_UID_ENV_KEY: ''}):
assert GuiProcessWatcher.get_gui_pid() is None

with patch.dict(os.environ, {GUI_UID_ENV_KEY: 'abc'}):
caplog.clear()
assert GuiProcessWatcher.get_gui_uid() is None
assert caplog.records[-1].message == 'Cannot parse TRIBLER_GUI_UID environment variable: abc'

with patch.dict(os.environ, {GUI_UID_ENV_KEY: '123'}):
assert GuiProcessWatcher.get_gui_uid() == 123


def test_get_gui_process():
# pid is not specified
with patch.dict(os.environ, {GUI_PID_ENV_KEY: ''}):
Expand Down
4 changes: 3 additions & 1 deletion src/tribler/core/start_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@
def run_core(api_port: Optional[int], api_key: Optional[str], root_state_dir, parsed_args):
logger.info(f"Running Core in {'gui_test_mode' if parsed_args.gui_test_mode else 'normal mode'}")

gui_uid = GuiProcessWatcher.get_gui_uid()

Check warning on line 189 in src/tribler/core/start_core.py

View check run for this annotation

Codecov / codecov/patch

src/tribler/core/start_core.py#L189

Added line #L189 was not covered by tests
gui_pid = GuiProcessWatcher.get_gui_pid()
current_process = TriblerProcess.current_process(ProcessKind.Core, creator_pid=gui_pid)
current_process = TriblerProcess.current_process(kind=ProcessKind.Core, creator_uid=gui_uid, creator_pid=gui_pid)

Check warning on line 191 in src/tribler/core/start_core.py

View check run for this annotation

Codecov / codecov/patch

src/tribler/core/start_core.py#L191

Added line #L191 was not covered by tests
process_manager = ProcessManager(root_state_dir, current_process)
set_global_process_manager(process_manager)
current_process_is_primary = process_manager.current_process.become_primary()
Expand All @@ -199,6 +200,7 @@
logger.warning(msg)
process_manager.sys_exit(1, msg)

current_process.start_updating_thread()

Check warning on line 203 in src/tribler/core/start_core.py

View check run for this annotation

Codecov / codecov/patch

src/tribler/core/start_core.py#L203

Added line #L203 was not covered by tests
version_history = VersionHistory(root_state_dir)
state_dir = version_history.code_version.directory
exit_code = run_tribler_core_session(api_port, api_key, state_dir, gui_test_mode=parsed_args.gui_test_mode)
Expand Down
28 changes: 18 additions & 10 deletions src/tribler/core/utilities/process_manager/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@

return 'unknown reason'

def primary_process_rowid(self, kind: ProcessKind) -> Optional[int]:
def primary_process_uid(self, kind: ProcessKind) -> Optional[int]:
"""
A helper method to load the current primary process of the specified kind from the database.

Expand All @@ -114,18 +114,26 @@
with self.connect() as connection:
cursor = connection.execute(f"""
SELECT {sql_scripts.SELECT_COLUMNS}
FROM processes WHERE kind = ? and "primary" = 1 ORDER BY rowid DESC LIMIT 1
FROM processes WHERE kind = ? and is_primary = 1 ORDER BY rowid
""", [kind.value])
row = cursor.fetchone()
if row is not None:
rows = cursor.fetchall()
primary_processes = []
for row in rows:
process = TriblerProcess.from_row(self, row)
if process.is_running():
return process.rowid
primary_processes.append(process)
else:
# Process is not running anymore; mark it as not primary
process.is_primary = False
process.save()

# Process is not running anymore; mark it as not primary
process.primary = False
process.save()
return None
if not primary_processes:
return None

if len(primary_processes) > 1:
raise RuntimeError(f'Several primary processes found of kind {kind}')

Check warning on line 134 in src/tribler/core/utilities/process_manager/manager.py

View check run for this annotation

Codecov / codecov/patch

src/tribler/core/utilities/process_manager/manager.py#L134

Added line #L134 was not covered by tests

return primary_processes[0].uid

def sys_exit(self, exit_code: Optional[int] = None, error: Optional[str | Exception] = None, replace: bool = False):
"""
Expand All @@ -141,7 +149,7 @@
sys.exit(exit_code)

@with_retry
def get_last_processes(self, limit=6) -> List[TriblerProcess]:
def get_last_processes(self, limit=10) -> List[TriblerProcess]:
"""
Returns last `limit` processes from the database. They are used during the formatting of the error report.
"""
Expand Down