diff --git a/ext/datadog.c b/ext/datadog.c index b0bb80c531f..4de884d3513 100644 --- a/ext/datadog.c +++ b/ext/datadog.c @@ -652,10 +652,6 @@ static PHP_RSHUTDOWN_FUNCTION(datadog) { bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup); #endif - if (DATADOG_G(remote_config_state)) { - datadog_rshutdown_remote_config(); - } - if (!datadog_disable) { dd_shutdown_observer(); } @@ -666,6 +662,11 @@ static PHP_RSHUTDOWN_FUNCTION(datadog) { datadog_sidecar_finalize(true); DATADOG_G(request_initialized) = false; + /* A signal may have queued a Remote Config reread during RSHUTDOWN. */ + DATADOG_G(reread_remote_configuration) = 0; + if (DATADOG_G(remote_config_state)) { + datadog_rshutdown_remote_config(); + } datadog_telemetry_rshutdown(); datadog_sidecar_rshutdown(); diff --git a/ext/remote_config.c b/ext/remote_config.c index 81aabbc7f2e..f7dc913fca4 100644 --- a/ext/remote_config.c +++ b/ext/remote_config.c @@ -21,10 +21,12 @@ static void dd_vm_interrupt(zend_execute_data *execute_data) { if (dd_prev_interrupt_function) { dd_prev_interrupt_function(execute_data); } - if (DATADOG_G(remote_config_state) && DATADOG_G(reread_remote_configuration)) { - LOG(INFO, "Rereading remote configurations after interrupt"); + if (DATADOG_G(reread_remote_configuration)) { DATADOG_G(reread_remote_configuration) = 0; - ddog_process_remote_configs(DATADOG_G(remote_config_state)); + if (DATADOG_G(request_initialized) && DATADOG_G(remote_config_state)) { + LOG(INFO, "Rereading remote configurations after interrupt"); + ddog_process_remote_configs(DATADOG_G(remote_config_state)); + } } } @@ -53,7 +55,9 @@ DATADOG_PUBLIC void datadog_set_all_thread_vm_interrupt(void) { } void datadog_check_for_new_config_now(void) { - if (DATADOG_G(remote_config_state) && !DATADOG_G(reread_remote_configuration) && ddog_process_remote_configs(DATADOG_G(remote_config_state))) { + if (DATADOG_G(request_initialized) && DATADOG_G(remote_config_state) && + !DATADOG_G(reread_remote_configuration) && + ddog_process_remote_configs(DATADOG_G(remote_config_state))) { // If we blocked the signal, notify the other threads too datadog_set_all_thread_vm_interrupt(); } diff --git a/ext/sidecar.c b/ext/sidecar.c index ca9706133fd..e5439e451cd 100644 --- a/ext/sidecar.c +++ b/ext/sidecar.c @@ -815,7 +815,7 @@ void ddtrace_sidecar_submit_span_data_direct(ddog_SidecarTransport **transport, const ddog_Vec_Tag *process_tags = datadog_process_tags_get_vec(); bool changed = true; - if (DATADOG_G(remote_config_state)) { + if (DATADOG_G(request_initialized) && DATADOG_G(remote_config_state)) { changed = ddog_remote_configs_service_env_change(DATADOG_G(remote_config_state), service_slice, env_slice, version_slice, &DATADOG_G(active_global_tags), process_tags); } @@ -853,7 +853,7 @@ void ddtrace_sidecar_submit_span_data_direct(ddog_SidecarTransport **transport, ddog_sidecar_telemetry_filter_flush(transport, datadog_sidecar_instance_id, &DATADOG_G(sidecar_queue_id), datadog_telemetry_buffer(), datadog_telemetry_cache(), service_slice, env_slice)); } - if (DATADOG_G(remote_config_state)) { + if (DATADOG_G(request_initialized) && DATADOG_G(remote_config_state)) { // Must happen after ddog_sidecar_set_universal_service_tags (session state fully initialized) ddog_process_remote_configs(DATADOG_G(remote_config_state)); } diff --git a/tests/ext/live-debugger/debugger_rshutdown_remote_config.phpt b/tests/ext/live-debugger/debugger_rshutdown_remote_config.phpt new file mode 100644 index 00000000000..5e48e7a306f --- /dev/null +++ b/tests/ext/live-debugger/debugger_rshutdown_remote_config.phpt @@ -0,0 +1,60 @@ +--TEST-- +Remote Config and live debugger hooks remain valid through tracer request shutdown +--SKIPIF-- + +--ENV-- +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 +DD_TRACE_AGENT_TEST_SESSION_TOKEN=live-debugger/rshutdown_remote_config +--INI-- +datadog.trace.enabled=1 +datadog.autofinish_spans=1 +--FILE-- +onClose[] = function () { + // The span is closed from tracer RSHUTDOWN. Remote Config and its + // live debugger subscriber must still be active. + var_dump(count(dd_trace_internal_fn('get_loaded_remote_configs'))); + echo "onClose completed\n"; + }; + } +} + +put_dynamic_config_file([ + "log_injection_enabled" => true, + "dynamic_instrumentation_enabled" => true, +]); + +await_probe_installation(function () { + build_span_probe(["where" => ["methodName" => "instrumented"]]); +}); + +$trigger = new StartSpanDuringShutdown(); + +echo "request body complete\n"; + +?> +--CLEAN-- + +--EXPECT-- +request body complete +int(2) +onClose completed diff --git a/tests/ext/remote_config/dynamic_config_late_shutdown.phpt b/tests/ext/remote_config/dynamic_config_late_shutdown.phpt new file mode 100644 index 00000000000..2be7889233b --- /dev/null +++ b/tests/ext/remote_config/dynamic_config_late_shutdown.phpt @@ -0,0 +1,64 @@ +--TEST-- +Remote config is not reapplied after its request shutdown cleanup +--SKIPIF-- + +--ENV-- +DD_AGENT_HOST=request-replayer +DD_TRACE_AGENT_PORT=80 +DD_TRACE_GENERATE_ROOT_SPAN=0 +DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.1 +DD_TRACE_AGENT_TEST_SESSION_TOKEN=remote-config/dynamic_config_late_shutdown +--FILE-- + true, +]); + +\DDTrace\start_span(); +if (ini_get('datadog.logs_injection') !== '1') { + dd_trace_internal_fn('await_remote_config'); +} +var_dump(ini_get('datadog.logs_injection')); + +stream_wrapper_register('late-remote-config', LateRemoteConfigWrapper::class); +$trigger = fopen('late-remote-config://trigger', 'r'); + +echo "request body complete\n"; + +?> +--CLEAN-- + +--EXPECT-- +string(1) "1" +request body complete +late close completed diff --git a/tracer/ddtrace.c b/tracer/ddtrace.c index df9b73ef12c..65f0434b255 100644 --- a/tracer/ddtrace.c +++ b/tracer/ddtrace.c @@ -628,7 +628,6 @@ void ddtrace_rshutdown(bool fast_shutdown) { ddtrace_clean_git_object(); ddtrace_weak_resources_rshutdown(); - ddtrace_live_debugger_rshutdown(); } void ddtrace_post_deactivate(void) { @@ -637,6 +636,7 @@ void ddtrace_post_deactivate(void) { zai_interceptor_deactivate(); // we can only actually free our hooks hashtables in post_deactivate, as within RSHUTDOWN some user code may still run + ddtrace_live_debugger_rshutdown(); zai_hook_rshutdown(); zai_uhook_rshutdown(); } diff --git a/tracer/functions.c b/tracer/functions.c index b0744e569b8..34bd35b302e 100644 --- a/tracer/functions.c +++ b/tracer/functions.c @@ -2215,6 +2215,10 @@ PHP_FUNCTION(dd_trace_internal_fn) { } else { array_init(return_value); } + } else if (FUNCTION_NAME_MATCHES("process_remote_config")) { + // Test/debug helper for exercising Remote Config at precise lifecycle points. + datadog_check_for_new_config_now(); + RETVAL_TRUE; } else if (FUNCTION_NAME_MATCHES("await_remote_config")) { uint32_t timeout_sec = 10; if (params_count == 1) {