Skip to content

feat(core): Stream extension trait - #1214

Open
lcian wants to merge 12 commits into
masterfrom
lcian/feat/stream-ext
Open

lcian wants to merge 12 commits into
masterfrom
lcian/feat/stream-ext

Conversation

@lcian

@lcian lcian commented Jun 30, 2026

Copy link
Copy Markdown
Member

Description

This adds an extension trait for futures_core::Stream that can be used to .bind_hub(...) on a stream, much like the existing machinery we have for futures.
This came up a few times already, and it happens to be one of the ways one could work around #1208 (given that the problematic response body is a stream, one can use such a stream wrapper to bind the current hub before converting that stream to a response -- I still think a proper separate fix should be introduced in the sentry-tower instrumentation though, as the user should not have to remember to do this manually. This is a more general construct that can be used in other scenarios too.

@github-actions

This comment has been minimized.

@lcian lcian changed the title lcian/feat/stream ext feat: Stream extension Jun 30, 2026
@lcian lcian changed the title feat: Stream extension feat(core): Stream extension trait Jun 30, 2026
Comment thread sentry-core/src/stream.rs
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let hub = self.hub.clone();
// https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
let stream = unsafe { self.map_unchecked_mut(|s| &mut s.stream) };

@lcian lcian Jun 30, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to avoid this direct usage of unsafe (and the one in SentryFuture) by adding a dependency to pin-project-lite.

@szokeasaurusrex

Copy link
Copy Markdown
Member

@lcian what is the status with this PR? Is it abandoned or are you still planning to finish it and get it ready for review?

@lcian
lcian marked this pull request as ready for review August 3, 2026 11:12
@lcian
lcian requested a review from a team as a code owner August 3, 2026 11:12
@lcian

lcian commented Aug 3, 2026

Copy link
Copy Markdown
Member Author

@szokeasaurusrex it's ready for review now, please take a look whenever you have time. I don't need this at the moment but it came up a couple times, so I think it would be a nice utility to have.

Comment thread sentry-core/src/stream.rs
Comment on lines +13 to +15
/// rather use the [`StreamExt::bind_hub`] method instead.
///
/// [`StreamExt::bind_hub`]: trait.StreamExt.html#method.bind_hub

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SentryStream docs point at non-existent StreamExt

Rustdoc names and links StreamExt::bind_hub, but the public trait is SentryStreamExt; update the prose and intra-doc link to match.

Evidence
  • SentryStream docs say users should call [StreamExt::bind_hub] and link trait.StreamExt.html#method.bind_hub.
  • The exported extension trait is pub trait SentryStreamExt with fn bind_hub, re-exported from sentry-core/src/lib.rs as SentryStreamExt.
  • No public StreamExt exists in this crate, so the rendered docs name and link are wrong.
Also found at 1 additional location
  • sentry-core/src/lib.rs:137

Identified by Warden · docs-review · KZT-QMP

@szokeasaurusrex szokeasaurusrex left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @lcian, apologies that it took me so long to get around to this.

I am requesting changes because this adds a dependency on futures-core to sentry-core, and we should try to avoid that 🙏 more details on inline comment

Comment thread sentry-core/Cargo.toml
metrics = []

[dependencies]
futures-core = { workspace = true }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

h: We should avoid adding dependencies when there is not a strong reason why we need the dependency.

In this case, I am not seeing a strong reason for sentry-core to depend on futures-core.

I see a few alternatives that would avoid this unconditional dependency:

  1. It seems we could probably provide the extension trait in a separate crate; perhaps we could name it sentry-futures, kinda like we do for integrations. The crate itself could perhaps later be evolved into a full-fledged integration.
  2. Alternatively, we can put the trait behind a feature-flag. Then, futures-core would be an optional dependency activated by that flag. If we go with this path, I would probably expose the trait in sentry, not sentry-core, unless there's a reason why it needs to be in sentry-core.

Comment thread sentry-core/src/stream.rs
Comment on lines +17 to +20
pub struct SentryStream<S> {
hub: Arc<Hub>,
stream: S,
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: If possible, I would make this type private, and adjust SentryStreamExt::bind_hub to return impl Stream<Self::Item>.

Suggested change
pub struct SentryStream<S> {
hub: Arc<Hub>,
stream: S,
}
struct SentryStream<S> {
hub: Arc<Hub>,
stream: S,
}

Comment thread sentry-core/src/stream.rs
Comment on lines +52 to +66
/// Stream extensions for Sentry.
pub trait SentryStreamExt: Sized {
/// Binds a hub to this stream.
///
/// This ensures that the stream is polled within the given hub.
fn bind_hub<H>(self, hub: H) -> SentryStream<Self>
where
H: Into<Arc<Hub>>,
{
SentryStream {
stream: self,
hub: hub.into(),
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to adjust this trait a bit in order to be able to return impl Stream

Suggested change
/// Stream extensions for Sentry.
pub trait SentryStreamExt: Sized {
/// Binds a hub to this stream.
///
/// This ensures that the stream is polled within the given hub.
fn bind_hub<H>(self, hub: H) -> SentryStream<Self>
where
H: Into<Arc<Hub>>,
{
SentryStream {
stream: self,
hub: hub.into(),
}
}
}
/// Stream extensions for Sentry.
pub trait SentryStreamExt: Sized + Stream {
/// Binds a hub to this stream.
///
/// This ensures that the stream is polled within the given hub.
fn bind_hub<H>(self, hub: H) -> impl Stream<Item = Self::Item>
where
H: Into<Arc<Hub>>,
{
SentryStream {
stream: self,
hub: hub.into(),
}
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants