@@ -782,4 +782,134 @@ mod tests {
782
782
"Metrics should be available in exporter."
783
783
) ;
784
784
}
785
+
786
+ async fn some_async_function ( ) -> u64 {
787
+ // No dependency on any particular async runtime.
788
+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 1 ) ) ;
789
+ 1
790
+ }
791
+
792
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
793
+ async fn async_inside_observable_callback_from_tokio_multi_with_one_worker ( ) {
794
+ async_inside_observable_callback_helper ( ) ;
795
+ }
796
+
797
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
798
+ async fn async_inside_observable_callback_from_tokio_multi_with_two_worker ( ) {
799
+ async_inside_observable_callback_helper ( ) ;
800
+ }
801
+
802
+ #[ tokio:: test( flavor = "current_thread" ) ]
803
+ async fn async_inside_observable_callback_from_tokio_current_thread ( ) {
804
+ async_inside_observable_callback_helper ( ) ;
805
+ }
806
+
807
+ #[ test]
808
+ fn async_inside_observable_callback_from_regular_main ( ) {
809
+ async_inside_observable_callback_helper ( ) ;
810
+ }
811
+
812
+ fn async_inside_observable_callback_helper ( ) {
813
+ let interval = std:: time:: Duration :: from_millis ( 10 ) ;
814
+ let exporter = InMemoryMetricExporter :: default ( ) ;
815
+ let reader = PeriodicReader :: builder ( exporter. clone ( ) )
816
+ . with_interval ( interval)
817
+ . build ( ) ;
818
+
819
+ let meter_provider = SdkMeterProvider :: builder ( ) . with_reader ( reader) . build ( ) ;
820
+ let meter = meter_provider. meter ( "test" ) ;
821
+ let _gauge = meter
822
+ . u64_observable_gauge ( "my_observable_gauge" )
823
+ . with_callback ( |observer| {
824
+ // using futures_executor::block_on intentionally and avoiding
825
+ // any particular async runtime.
826
+ let value = futures_executor:: block_on ( some_async_function ( ) ) ;
827
+ observer. observe ( value, & [ ] ) ;
828
+ } )
829
+ . build ( ) ;
830
+
831
+ meter_provider. force_flush ( ) . expect ( "flush should succeed" ) ;
832
+ let exported_metrics = exporter
833
+ . get_finished_metrics ( )
834
+ . expect ( "this should not fail" ) ;
835
+ assert ! (
836
+ !exported_metrics. is_empty( ) ,
837
+ "Metrics should be available in exporter."
838
+ ) ;
839
+ }
840
+
841
+ async fn some_tokio_async_function ( ) -> u64 {
842
+ // Tokio specific async function
843
+ tokio:: time:: sleep ( Duration :: from_millis ( 1 ) ) . await ;
844
+ 1
845
+ }
846
+
847
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
848
+
849
+ async fn tokio_async_inside_observable_callback_from_tokio_multi_with_one_worker ( ) {
850
+ tokio_async_inside_observable_callback_helper ( true ) ;
851
+ }
852
+
853
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
854
+ async fn tokio_async_inside_observable_callback_from_tokio_multi_with_two_worker ( ) {
855
+ tokio_async_inside_observable_callback_helper ( true ) ;
856
+ }
857
+
858
+ #[ tokio:: test( flavor = "current_thread" ) ]
859
+ #[ ignore] //TODO: Investigate if this can be fixed.
860
+ async fn tokio_async_inside_observable_callback_from_tokio_current_thread ( ) {
861
+ tokio_async_inside_observable_callback_helper ( true ) ;
862
+ }
863
+
864
+ #[ test]
865
+ fn tokio_async_inside_observable_callback_from_regular_main ( ) {
866
+ tokio_async_inside_observable_callback_helper ( false ) ;
867
+ }
868
+
869
+ fn tokio_async_inside_observable_callback_helper ( use_current_tokio_runtime : bool ) {
870
+ let interval = std:: time:: Duration :: from_millis ( 10 ) ;
871
+ let exporter = InMemoryMetricExporter :: default ( ) ;
872
+ let reader = PeriodicReader :: builder ( exporter. clone ( ) )
873
+ . with_interval ( interval)
874
+ . build ( ) ;
875
+
876
+ let meter_provider = SdkMeterProvider :: builder ( ) . with_reader ( reader) . build ( ) ;
877
+ let meter = meter_provider. meter ( "test" ) ;
878
+
879
+ if use_current_tokio_runtime {
880
+ let rt = tokio:: runtime:: Handle :: current ( ) . clone ( ) ;
881
+ let _gauge = meter
882
+ . u64_observable_gauge ( "my_observable_gauge" )
883
+ . with_callback ( move |observer| {
884
+ // call tokio specific async function from here
885
+ let value = rt. block_on ( some_tokio_async_function ( ) ) ;
886
+ observer. observe ( value, & [ ] ) ;
887
+ } )
888
+ . build ( ) ;
889
+ // rt here is a reference to the current tokio runtime.
890
+ // Droppng it occurs when the tokio::main itself ends.
891
+ } else {
892
+ let rt = tokio:: runtime:: Runtime :: new ( ) . unwrap ( ) ;
893
+ let _gauge = meter
894
+ . u64_observable_gauge ( "my_observable_gauge" )
895
+ . with_callback ( move |observer| {
896
+ // call tokio specific async function from here
897
+ let value = rt. block_on ( some_tokio_async_function ( ) ) ;
898
+ observer. observe ( value, & [ ] ) ;
899
+ } )
900
+ . build ( ) ;
901
+ // rt is not dropped here as it is moved to the closure,
902
+ // and is dropped only when MeterProvider itself is dropped.
903
+ // This works when called from normal main.
904
+ } ;
905
+
906
+ meter_provider. force_flush ( ) . expect ( "flush should succeed" ) ;
907
+ let exported_metrics = exporter
908
+ . get_finished_metrics ( )
909
+ . expect ( "this should not fail" ) ;
910
+ assert ! (
911
+ !exported_metrics. is_empty( ) ,
912
+ "Metrics should be available in exporter."
913
+ ) ;
914
+ }
785
915
}
0 commit comments