Skip to content

Commit 155d00a

Browse files
authored
feat: runtime-independent background event transport (#145)
1 parent 1888fc3 commit 155d00a

26 files changed

Lines changed: 2615 additions & 878 deletions
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
posthog-rs: minor
3+
---
4+
5+
Runtime-independent background event transport. `capture` and `capture_batch` are now non-blocking enqueues onto a background worker — a plain `std::thread` with a blocking HTTP client, independent of any async runtime — that batches events, retries transient failures with backoff (honoring `Retry-After`), and sends them. They no longer block on the network or return delivery errors.
6+
7+
New public API: `flush()` (awaited on the async client, blocking on the blocking client), `shutdown()` (flush + stop the worker + join; idempotent; drops further captures), and flush-on-`Drop`. New `ClientOptions`: `flush_at`, `max_batch_size`, `flush_interval_ms`, `max_queue_size` (a bounded queue that drops with a single warning when full), and `shutdown_timeout_ms` (bounds the shutdown/`Drop` drain). `before_send` hooks now run on the worker thread, so they apply to every queued event.
8+
9+
Breaking change (0.x): `capture` and `capture_batch` no longer return a `Result` — and are no longer `async` on the async client. They enqueue the event and return immediately (infallibly) instead of awaiting delivery; transient HTTP failures surface as logged warnings rather than `Err`. Call `flush()` or `shutdown()` before process exit to ensure queued events are delivered.

api/public-api.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,21 @@ pub struct posthog_rs::CaptureResponse
101101
pub posthog_rs::CaptureResponse::results: std::collections::hash::map::HashMap<uuid::Uuid, posthog_rs::EventResult>
102102
pub struct posthog_rs::Client
103103
impl posthog_rs::Client
104-
pub async fn posthog_rs::Client::capture(&self, posthog_rs::Event) -> core::result::Result<(), posthog_rs::Error>
105-
pub async fn posthog_rs::Client::capture_batch(&self, alloc::vec::Vec<posthog_rs::Event>, bool) -> core::result::Result<(), posthog_rs::Error>
104+
pub fn posthog_rs::Client::capture(&self, posthog_rs::Event)
105+
pub fn posthog_rs::Client::capture_batch(&self, alloc::vec::Vec<posthog_rs::Event>, bool)
106106
pub async fn posthog_rs::Client::capture_exception<E>(&self, &E) -> core::result::Result<(), posthog_rs::Error> where E: core::error::Error + ?core::marker::Sized
107107
pub async fn posthog_rs::Client::capture_exception_with<E>(&self, &E, posthog_rs::CaptureExceptionOptions) -> core::result::Result<(), posthog_rs::Error> where E: core::error::Error + ?core::marker::Sized
108108
pub fn posthog_rs::Client::evaluate_feature_flag_locally(&self, &posthog_rs::FeatureFlag, &str, &std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>, &std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>, &std::collections::hash::map::HashMap<alloc::string::String, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>) -> core::result::Result<posthog_rs::FlagValue, posthog_rs::Error>
109109
pub async fn posthog_rs::Client::evaluate_flags<S: core::convert::Into<alloc::string::String>>(&self, S, posthog_rs::EvaluateFlagsOptions) -> core::result::Result<posthog_rs::FeatureFlagEvaluations, posthog_rs::Error>
110+
pub async fn posthog_rs::Client::flush(&self)
110111
pub async fn posthog_rs::Client::get_feature_flag<K: core::convert::Into<alloc::string::String>, D: core::convert::Into<alloc::string::String>>(&self, K, D, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>>) -> core::result::Result<core::option::Option<posthog_rs::FlagValue>, posthog_rs::Error>
111112
pub async fn posthog_rs::Client::get_feature_flag_payload<K: core::convert::Into<alloc::string::String>, D: core::convert::Into<alloc::string::String>>(&self, K, D) -> core::result::Result<core::option::Option<serde_json::value::Value>, posthog_rs::Error>
112113
pub async fn posthog_rs::Client::get_feature_flags<S: core::convert::Into<alloc::string::String>>(&self, S, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>>) -> core::result::Result<(std::collections::hash::map::HashMap<alloc::string::String, posthog_rs::FlagValue>, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>), posthog_rs::Error>
113114
pub async fn posthog_rs::Client::is_feature_enabled<K: core::convert::Into<alloc::string::String>, D: core::convert::Into<alloc::string::String>>(&self, K, D, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>, core::option::Option<std::collections::hash::map::HashMap<alloc::string::String, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>>) -> core::result::Result<bool, posthog_rs::Error>
115+
pub fn posthog_rs::Client::pending_events(&self) -> usize
116+
pub async fn posthog_rs::Client::shutdown(&self)
117+
impl core::ops::drop::Drop for posthog_rs::Client
118+
pub fn posthog_rs::Client::drop(&mut self)
114119
pub struct posthog_rs::ClientOptions
115120
impl posthog_rs::ClientOptions
116121
pub fn posthog_rs::ClientOptions::is_disabled(&self) -> bool
@@ -128,15 +133,20 @@ pub fn posthog_rs::ClientOptionsBuilder::enable_local_evaluation(&mut self, bool
128133
pub fn posthog_rs::ClientOptionsBuilder::error_tracking(&mut self, posthog_rs::ErrorTrackingOptions) -> &mut Self
129134
pub fn posthog_rs::ClientOptionsBuilder::extra_capture_headers(&mut self, std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> &mut Self
130135
pub fn posthog_rs::ClientOptionsBuilder::feature_flags_request_timeout_seconds(&mut self, u64) -> &mut Self
136+
pub fn posthog_rs::ClientOptionsBuilder::flush_at(&mut self, usize) -> &mut Self
137+
pub fn posthog_rs::ClientOptionsBuilder::flush_interval_ms(&mut self, u64) -> &mut Self
131138
pub fn posthog_rs::ClientOptionsBuilder::host<VALUE: core::convert::Into<alloc::string::String>>(&mut self, VALUE) -> &mut Self
132139
pub fn posthog_rs::ClientOptionsBuilder::is_server(&mut self, bool) -> &mut Self
133140
pub fn posthog_rs::ClientOptionsBuilder::local_evaluation_only(&mut self, bool) -> &mut Self
141+
pub fn posthog_rs::ClientOptionsBuilder::max_batch_size(&mut self, usize) -> &mut Self
134142
pub fn posthog_rs::ClientOptionsBuilder::max_capture_attempts(&mut self, u32) -> &mut Self
143+
pub fn posthog_rs::ClientOptionsBuilder::max_queue_size(&mut self, usize) -> &mut Self
135144
pub fn posthog_rs::ClientOptionsBuilder::personal_api_key<VALUE: core::convert::Into<alloc::string::String>>(&mut self, VALUE) -> &mut Self
136145
pub fn posthog_rs::ClientOptionsBuilder::poll_interval_seconds(&mut self, u64) -> &mut Self
137146
pub fn posthog_rs::ClientOptionsBuilder::request_timeout_seconds(&mut self, u64) -> &mut Self
138147
pub fn posthog_rs::ClientOptionsBuilder::retry_initial_backoff_ms(&mut self, u64) -> &mut Self
139148
pub fn posthog_rs::ClientOptionsBuilder::retry_max_backoff_ms(&mut self, u64) -> &mut Self
149+
pub fn posthog_rs::ClientOptionsBuilder::shutdown_timeout_ms(&mut self, u64) -> &mut Self
140150
impl posthog_rs::ClientOptionsBuilder
141151
pub fn posthog_rs::ClientOptionsBuilder::before_send<F>(&mut self, F) -> &mut Self where F: core::ops::function::FnMut(posthog_rs::Event) -> core::option::Option<posthog_rs::Event> + core::marker::Send + 'static
142152
pub fn posthog_rs::ClientOptionsBuilder::build(&self) -> core::result::Result<posthog_rs::ClientOptions, posthog_rs::ClientOptionsBuilderError>
@@ -302,13 +312,15 @@ pub posthog_rs::Property::value: serde_json::value::Value
302312
pub const posthog_rs::DEFAULT_HOST: &str
303313
pub const posthog_rs::EU_INGESTION_ENDPOINT: &str
304314
pub const posthog_rs::US_INGESTION_ENDPOINT: &str
305-
pub async fn posthog_rs::capture(posthog_rs::Event) -> core::result::Result<(), posthog_rs::Error>
315+
pub fn posthog_rs::capture(posthog_rs::Event)
306316
pub async fn posthog_rs::capture_exception<E>(&E) -> core::result::Result<(), posthog_rs::Error> where E: core::error::Error + ?core::marker::Sized
307317
pub async fn posthog_rs::capture_exception_with<E>(&E, posthog_rs::CaptureExceptionOptions) -> core::result::Result<(), posthog_rs::Error> where E: core::error::Error + ?core::marker::Sized
308318
pub async fn posthog_rs::client<C: core::convert::Into<posthog_rs::ClientOptions>>(C) -> posthog_rs::Client
309319
pub fn posthog_rs::disable_global()
320+
pub async fn posthog_rs::flush()
310321
pub fn posthog_rs::global_is_disabled() -> bool
311322
pub async fn posthog_rs::init_global<C: core::convert::Into<posthog_rs::ClientOptions>>(C) -> core::result::Result<(), posthog_rs::Error>
312323
pub fn posthog_rs::match_feature_flag(&posthog_rs::FeatureFlag, &str, &std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>, &std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>, &std::collections::hash::map::HashMap<alloc::string::String, std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>>, &std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::result::Result<posthog_rs::FlagValue, posthog_rs::InconclusiveMatchError>
313324
pub fn posthog_rs::match_feature_flag_with_context(&posthog_rs::FeatureFlag, &std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>, &posthog_rs::EvaluationContext<'_>) -> core::result::Result<posthog_rs::FlagValue, posthog_rs::InconclusiveMatchError>
314325
pub fn posthog_rs::match_property_with_context(&posthog_rs::Property, &std::collections::hash::map::HashMap<alloc::string::String, serde_json::value::Value>, &posthog_rs::EvaluationContext<'_>) -> core::result::Result<bool, posthog_rs::InconclusiveMatchError>
326+
pub async fn posthog_rs::shutdown()

0 commit comments

Comments
 (0)