diff --git a/ddtrace/internal/symbol_db/remoteconfig.py b/ddtrace/internal/symbol_db/remoteconfig.py index feccaa806c1..78eca1a087d 100644 --- a/ddtrace/internal/symbol_db/remoteconfig.py +++ b/ddtrace/internal/symbol_db/remoteconfig.py @@ -19,7 +19,7 @@ log = get_logger(__name__) -def _rc_callback(data: t.List[Payload], test_tracer=None): +def _rc_callback(data: t.Sequence[Payload]): if get_ancestor_runtime_id() is not None and has_forked(): log.debug("[PID %d] SymDB: Disabling Symbol DB in forked process", os.getpid()) # We assume that forking is being used for spawning child worker diff --git a/tests/internal/symbol_db/test_symbols.py b/tests/internal/symbol_db/test_symbols.py index bfd89a20c8f..27425debc3f 100644 --- a/tests/internal/symbol_db/test_symbols.py +++ b/tests/internal/symbol_db/test_symbols.py @@ -286,3 +286,37 @@ def get_scope(contexts, name): scope = get_scope(contexts, "tests.submod.stuff") assert scope["scope_type"] == ScopeType.MODULE assert scope["name"] == "tests.submod.stuff" + + +@pytest.mark.subprocess(ddtrace_run=True, err=None) +def test_symbols_fork_uploads(): + """ + Test that we disable Symbol DB on processes that are not the main one nor + the first fork child. + """ + import os + + from ddtrace.internal import forksafe + from ddtrace.internal.remoteconfig import ConfigMetadata + from ddtrace.internal.remoteconfig import Payload + from ddtrace.internal.runtime import get_ancestor_runtime_id + from ddtrace.internal.symbol_db.remoteconfig import _rc_callback + from ddtrace.internal.symbol_db.symbols import SymbolDatabaseUploader + + SymbolDatabaseUploader.install() + + pids = [] + rc_data = [Payload(ConfigMetadata("test", "symdb", "hash", 0, 0), "test", None)] + + for _ in range(10): + if not (pid := os.fork()): + _rc_callback(rc_data) + assert SymbolDatabaseUploader.is_installed() != ( + get_ancestor_runtime_id() is not None and forksafe.has_forked() + ) + os._exit(0) + + pids.append(pid) + + for pid in pids: + os.waitpid(pid, 0)