Skip to content

[Bug]: PeriodicReader::shutdown() deadlocks on current thread runtime. #2056

@inahga

Description

@inahga

What happened?

When using the SdkMeterProvider with a PeriodicReader on a tokio current_thread runtime, the program hangs when the SdkMeterProvider leaves scope.

Example reproducer: Take the registration_triggers_collection() test function in opentelemetry-sdk/src/metrics/periodic_reader.rs, and run it on a current_thread runtime:

    #[tokio::test]
    async fn registration_triggers_collection() {
        // Arrange
        let interval = std::time::Duration::from_millis(1);
        let exporter = InMemoryMetricsExporter::default();
        let reader = PeriodicReader::builder(exporter.clone(), runtime::Tokio)
            .with_interval(interval)
            .build();
        let (sender, receiver) = mpsc::channel();

        // Act
        let meter_provider = SdkMeterProvider::builder().with_reader(reader).build();
        let meter = meter_provider.meter("test");
        let _counter = meter
            .u64_observable_counter("testcounter")
            .with_callback(move |_| {
                sender.send(()).expect("channel should still be open");
            })
            .init();

        _ = meter_provider.force_flush();

        // Assert
        receiver
            .try_recv()
            .expect("message should be available in channel, indicating a collection occurred");
    }

The problematic code looks to be in PeriodicReader::shutdown(), where we send a shutdown signal and wait for receipt on a oneshot channel in a block_on statement. When executed in the context of a Drop, there is no runtime to advance the other side of the channel, so we hang indefinitely.

It's not a big deal, it can be worked around by using a multi-thread runtime, or by calling shutdown() ahead of time. It's just unexpected and easy to trip up on, since tokio tests default to a current thread runtime.

More than happy to fix it myself, but wanted to get maintainer input first. (It may be the right answer is to not use a current thread runtime?)

API Version

0.24.0

SDK Version

0.24.1

What Exporter(s) are you seeing the problem on?

N/A

Relevant log output

No response

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions