|
237 | 237 | //! |
238 | 238 | //! Anything that falls outside of that will require changing the client-key. |
239 | 239 | //! |
| 240 | +//! ## Sending Telemetry |
| 241 | +//! |
| 242 | +//! [`SiftStream`] exposes four methods for delivering telemetry. They differ only in whether |
| 243 | +//! they apply backpressure (blocking) or return immediately (non-blocking), and in whether |
| 244 | +//! they accept a high-level [`Flow`] or pre-encoded raw requests: |
| 245 | +//! |
| 246 | +//! | Method | Blocks? | Input | |
| 247 | +//! |---|---|---| |
| 248 | +//! | [`send`](stream::SiftStream::send) | Yes | [`Flow`] or any [`Encodeable`](stream::Encodeable) | |
| 249 | +//! | [`send_requests`](stream::SiftStream::send_requests) | Yes | Pre-encoded requests | |
| 250 | +//! | [`try_send`](stream::SiftStream::try_send) | No | [`Flow`] or any [`Encodeable`](stream::Encodeable) | |
| 251 | +//! | [`try_send_requests`](stream::SiftStream::try_send_requests) | No | Pre-encoded requests | |
| 252 | +//! |
| 253 | +//! ### Backpressure with `send` |
| 254 | +//! |
| 255 | +//! [`send`](stream::SiftStream::send) awaits until the backing channel has capacity, then |
| 256 | +//! delivers the message. Use this when you want the producer to slow down naturally when |
| 257 | +//! the pipeline is under load — the simplest and most common choice. |
| 258 | +//! |
| 259 | +//! ```ignore |
| 260 | +//! // Awaits until the channel has room; backpressure is applied automatically. |
| 261 | +//! sift_stream.send(Flow::new( |
| 262 | +//! "robotic-arm", |
| 263 | +//! TimeValue::now(), |
| 264 | +//! &[ChannelValue::new("joint-angle-encoder", 7.2_f64)], |
| 265 | +//! )).await?; |
| 266 | +//! ``` |
| 267 | +//! |
| 268 | +//! On error, [`SiftStreamSendError`] is returned. Call `into_inner()` on the |
| 269 | +//! [`ChannelClosed`](stream::SiftStreamSendError::ChannelClosed) variant to recover the |
| 270 | +//! undelivered message. |
| 271 | +//! |
| 272 | +//! ### Non-blocking sends with `try_send` |
| 273 | +//! |
| 274 | +//! [`try_send`](stream::SiftStream::try_send) returns immediately regardless of channel |
| 275 | +//! state. If the channel is full it returns [`TrySendError::Full`] with the message; if |
| 276 | +//! the channel is closed it returns [`TrySendError::Closed`]. Use this in tight loops or |
| 277 | +//! real-time contexts where blocking even briefly is unacceptable. |
| 278 | +//! |
| 279 | +//! ```ignore |
| 280 | +//! match sift_stream.try_send(Flow::new( |
| 281 | +//! "robotic-arm", |
| 282 | +//! TimeValue::now(), |
| 283 | +//! &[ChannelValue::new("joint-angle-encoder", 7.2_f64)], |
| 284 | +//! )) { |
| 285 | +//! Ok(()) => {} |
| 286 | +//! Err(SiftStreamTrySendError::Channel(TrySendError::Full(msg))) => { |
| 287 | +//! // Channel is busy — drop this sample or buffer it for later. |
| 288 | +//! drop(msg); |
| 289 | +//! } |
| 290 | +//! Err(e) => return Err(e.into()), |
| 291 | +//! } |
| 292 | +//! ``` |
| 293 | +//! |
| 294 | +//! ### Pre-encoded batch sends |
| 295 | +//! |
| 296 | +//! [`send_requests`](stream::SiftStream::send_requests) and |
| 297 | +//! [`try_send_requests`](stream::SiftStream::try_send_requests) accept pre-encoded |
| 298 | +//! [`IngestWithConfigDataStreamRequest`](sift_rs::ingest::v1::IngestWithConfigDataStreamRequest) |
| 299 | +//! values built with [`FlowBuilder`]. This skips the per-call encoding step and is the |
| 300 | +//! highest-throughput option. |
| 301 | +//! |
| 302 | +//! ```ignore |
| 303 | +//! let descriptor = sift_stream.get_flow_descriptor("robotic-arm").unwrap(); |
| 304 | +//! let run_id = sift_stream.run().unwrap().run_id.clone(); |
| 305 | +//! |
| 306 | +//! let mut builder = FlowBuilder::new(&descriptor); |
| 307 | +//! builder.attach_run_id(&run_id); |
| 308 | +//! builder.set_with_key("joint-angle-encoder", 7.2_f64).unwrap(); |
| 309 | +//! |
| 310 | +//! // Blocking batch send with backpressure: |
| 311 | +//! sift_stream.send_requests(vec![builder.request(TimeValue::now())]).await?; |
| 312 | +//! |
| 313 | +//! // Non-blocking batch send: |
| 314 | +//! sift_stream.try_send_requests(vec![builder.request(TimeValue::now())])?; |
| 315 | +//! ``` |
| 316 | +//! |
| 317 | +//! On the first failure, `send_requests` / `try_send_requests` stop iterating and return |
| 318 | +//! **all** undelivered messages — the failing one plus any not yet attempted — inside the |
| 319 | +//! error so nothing is silently dropped. |
| 320 | +//! |
240 | 321 | //! ## Retry Policy |
241 | 322 | //! |
242 | 323 | //! At the time of writing this crate, [tonic](https://docs.rs/tonic/latest/tonic/) |
@@ -456,6 +537,7 @@ pub use stream::{ |
456 | 537 | file_backup::FileBackup, |
457 | 538 | ingestion_config::{Flow, IngestionConfigEncoder, LiveStreaming}, |
458 | 539 | }, |
| 540 | + send_error::{SendError, SiftStreamSendError, SiftStreamTrySendError, TrySendError}, |
459 | 541 | time::TimeValue, |
460 | 542 | }; |
461 | 543 |
|
|
0 commit comments