Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref: Improve Hub concurrency docs #509

Merged
merged 2 commits into from Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions sentry-core/Cargo.toml
Expand Up @@ -55,4 +55,6 @@ sentry = { path = "../sentry", default-features = false, features = ["test", "tr
thiserror = "1.0.15"
anyhow = "1.0.30"
tokio = { version = "1.0", features = ["rt", "rt-multi-thread", "macros"] }
futures = "0.3.24"
rayon = "1.5.3"
criterion = "0.3"
3 changes: 2 additions & 1 deletion sentry-core/src/hub.rs
Expand Up @@ -77,7 +77,8 @@ impl HubImpl {
/// toplevel convenience functions are expose that will automatically dispatch
/// to the thread-local ([`Hub::current`]) hub. In some situations this might not be
/// possible in which case it might become necessary to manually work with the
/// hub. This is for instance the case when working with async code.
/// hub. See the main [`crate`] docs for some common use-cases and pitfalls
/// related to parallel, concurrent or async code.
///
/// Hubs that are wrapped in [`Arc`]s can be bound to the current thread with
/// the `run` static method.
Expand Down
68 changes: 62 additions & 6 deletions sentry-core/src/lib.rs
Expand Up @@ -14,6 +14,68 @@
//! the concepts of [`Client`], [`Hub`] and [`Scope`], as well as the extension
//! points via the [`Integration`], [`Transport`] and [`TransportFactory`] traits.
//!
//! # Parallelism, Concurrency and Async
//!
//! The main concurrency primitive is the [`Hub`]. In general, all concurrent
//! code, no matter if multithreaded parallelism, or futures concurrency needs
Swatinem marked this conversation as resolved.
Show resolved Hide resolved
//! to run with its own copy of a Hub. Even though the [`Hub`] is internally
Swatinem marked this conversation as resolved.
Show resolved Hide resolved
//! synchronized, using it concurrently may lead to unexpected results up to
//! panics.
//!
//! For threads or tasks that are running concurrently or outlive the current
//! execution context, a new [`Hub`] needs to be created and bound for the computation.
//!
//! ```rust
//! # let rt = tokio::runtime::Runtime::new().unwrap();
//! # rt.block_on(async {
//! use rayon::prelude::*;
//! use sentry::{Hub, SentryFutureExt};
//! use std::sync::Arc;
//!
//! // Parallel multithreaded code:
//! let outer_hub = Hub::current();
//! let results: Vec<_> = [1_u32, 2, 3]
//! .into_par_iter()
//! .map(|num| {
//! let thread_hub = Arc::new(Hub::new_from_top(&outer_hub));
//! Hub::run(thread_hub, || num * num)
//! })
//! .collect();
//!
//! assert_eq!(&results, &[1, 4, 9]);
//!
//! // Concurrent futures code:
//! let futures = [1_u32, 2, 3]
//! .into_iter()
//! .map(|num| async move { num * num }.bind_hub(Hub::new_from_top(Hub::current())));
//! let results = futures::future::join_all(futures).await;
//!
//! assert_eq!(&results, &[1, 4, 9]);
//! # });
//! ```
//!
//! For tasks that are not concurrent and do not outlive the current execution
//! context, no *new* [`Hub`] needs to be created, but the current [`Hub`] has
//! to be bound.
//!
//! ```rust
//! # let rt = tokio::runtime::Runtime::new().unwrap();
//! # rt.block_on(async {
//! use sentry::{Hub, SentryFutureExt};
//!
//! // Spawned thread that is being joined:
//! let hub = Hub::current();
//! let result = std::thread::spawn(|| Hub::run(hub, || 1_u32)).join();
//!
//! assert_eq!(result.unwrap(), 1);
//!
//! // Spawned future that is being awaited:
//! let result = tokio::spawn(async { 1_u32 }.bind_hub(Hub::current())).await;
//!
//! assert_eq!(result.unwrap(), 1);
//! # });
//! ```
//!
//! # Minimal API
//!
//! By default, this crate comes with a so-called "minimal" mode. This mode will
Expand All @@ -38,12 +100,6 @@
//! [Sentry]: https://sentry.io/
//! [`sentry`]: https://crates.io/crates/sentry
//! [Unified API]: https://develop.sentry.dev/sdk/unified-api/
//! [`Client`]: struct.Client.html
//! [`Hub`]: struct.Hub.html
//! [`Scope`]: struct.Scope.html
//! [`Integration`]: trait.Integration.html
//! [`Transport`]: trait.Transport.html
//! [`TransportFactory`]: trait.TransportFactory.html
//! [`test`]: test/index.html

#![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")]
Expand Down
1 change: 0 additions & 1 deletion sentry-types/src/protocol/envelope.rs
Expand Up @@ -108,7 +108,6 @@ pub enum EnvelopeItem {
/// for more details.
Attachment(Attachment),
/// An Profile Item.
///
Profile(SampleProfile),
// TODO:
// etc…
Expand Down
4 changes: 3 additions & 1 deletion sentry/src/lib.rs
Expand Up @@ -8,7 +8,8 @@
//!
//! The most convenient way to use this library is via the [`sentry::init`] function,
//! which starts a sentry client with a default set of integrations, and binds
//! it to the current [`Hub`].
//! it to the current [`Hub`]. More Information on how to use Sentry in parallel,
//! concurrent and async scenarios can be found on the [`Hub`] docs as well.
//!
//! The [`sentry::init`] function returns a guard that when dropped will flush Events that were not
//! yet sent to the sentry service. It has a two second deadline for this so shutdown of
Expand Down Expand Up @@ -110,6 +111,7 @@
//!
//! ## Integrations
//! - `tower`: Enables support for the `tower` crate and those using it.

#![doc(html_favicon_url = "https://sentry-brand.storage.googleapis.com/favicon.ico")]
#![doc(html_logo_url = "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png")]
#![warn(missing_docs)]
Expand Down