Skip to content

Commit f8bc43d

Browse files
committed
Add fork safety native methods to TraceExporter
Expose `_native_before_fork`, `_native_after_fork_in_parent`, and `_native_after_fork_in_child` instance methods that delegate to libdatadog's SharedRuntime fork hooks. These coordinate the tokio runtime lifecycle around process forks (Puma, Unicorn, Passenger).
1 parent 66f6fa8 commit f8bc43d

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

ext/libdatadog_api/trace_exporter.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ static VALUE _native_from_span(VALUE klass, VALUE span);
2020
/* TraceExporter methods */
2121
static VALUE _native_exporter_new(int argc, VALUE *argv, VALUE klass);
2222
static VALUE _native_send_traces(VALUE self, VALUE traces);
23+
static VALUE _native_before_fork(VALUE self);
24+
static VALUE _native_after_fork_in_parent(VALUE self);
25+
static VALUE _native_after_fork_in_child(VALUE self);
2326

2427
/* Response helpers */
2528
static VALUE create_ok_response(long trace_count, VALUE payload);
@@ -473,6 +476,46 @@ static VALUE _native_exporter_new(
473476
exporter);
474477
}
475478

479+
/* ========================================================================
480+
* Fork safety hooks
481+
*
482+
* These coordinate the tokio runtime lifecycle around process forks
483+
* (Puma, Unicorn, Passenger).
484+
* ======================================================================== */
485+
486+
static VALUE _native_before_fork(VALUE self) {
487+
ddog_TraceExporter *exporter;
488+
TypedData_Get_Struct(self, ddog_TraceExporter, &trace_exporter_typed_data, exporter);
489+
if (exporter == NULL) {
490+
raise_error(rb_eRuntimeError, "TraceExporter has not been initialized or was already freed");
491+
}
492+
ddog_TraceExporterError *err = ddog_trace_exporter_before_fork(exporter);
493+
check_exporter_error("Failed to prepare for fork", err);
494+
return Qnil;
495+
}
496+
497+
static VALUE _native_after_fork_in_parent(VALUE self) {
498+
ddog_TraceExporter *exporter;
499+
TypedData_Get_Struct(self, ddog_TraceExporter, &trace_exporter_typed_data, exporter);
500+
if (exporter == NULL) {
501+
raise_error(rb_eRuntimeError, "TraceExporter has not been initialized or was already freed");
502+
}
503+
ddog_TraceExporterError *err = ddog_trace_exporter_after_fork_in_parent(exporter);
504+
check_exporter_error("Failed to restore after fork in parent", err);
505+
return Qnil;
506+
}
507+
508+
static VALUE _native_after_fork_in_child(VALUE self) {
509+
ddog_TraceExporter *exporter;
510+
TypedData_Get_Struct(self, ddog_TraceExporter, &trace_exporter_typed_data, exporter);
511+
if (exporter == NULL) {
512+
raise_error(rb_eRuntimeError, "TraceExporter has not been initialized or was already freed");
513+
}
514+
ddog_TraceExporterError *err = ddog_trace_exporter_after_fork_in_child(exporter);
515+
check_exporter_error("Failed to restore after fork in child", err);
516+
return Qnil;
517+
}
518+
476519
/* ========================================================================
477520
* GVL-release helper for ddog_trace_exporter_send_trace_chunks
478521
*
@@ -736,6 +779,14 @@ void trace_exporter_init(VALUE tracing_module) {
736779
rb_define_method(trace_exporter_class, "_native_send_traces",
737780
_native_send_traces, 1);
738781

782+
/* Instance: fork safety hooks */
783+
rb_define_method(trace_exporter_class, "_native_before_fork",
784+
_native_before_fork, 0);
785+
rb_define_method(trace_exporter_class, "_native_after_fork_in_parent",
786+
_native_after_fork_in_parent, 0);
787+
rb_define_method(trace_exporter_class, "_native_after_fork_in_child",
788+
_native_after_fork_in_child, 0);
789+
739790
/* ----------------------------------------------------------------
740791
* Response class (defined in Ruby, loaded lazily)
741792
*

0 commit comments

Comments
 (0)