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

Make SSE less dependent on tokio #3153

Open
1 task done
nanoqsh opened this issue Jan 7, 2025 · 0 comments
Open
1 task done

Make SSE less dependent on tokio #3153

nanoqsh opened this issue Jan 7, 2025 · 0 comments

Comments

@nanoqsh
Copy link

nanoqsh commented Jan 7, 2025

  • I have looked for existing issues (including closed) about this

Feature Request

Make server-sent events less dependent on the Tokio feature

Motivation

Currently, to return an SSE response the tokio feature is required, even though Tokio runtime is only needed for timeouts to maintain keep-alive connection. This limitation restricts the use of SSE with other runtimes.

Proposal

I propose to remove the strict dependency of tokio feature for SSE and leave it only for keep-alive events.

This would be useful in cases such as:

  • When axum is used with a different runtime.
  • When keep-alive events aren't needed. For example I know that messages from my stream are sent frequently enough.

In addition to the proposal, I have an implementation. I explored several other implementation options and eventually came up with a design that I believe is the simplest and also allows for easy customization of keep-alive event handling for arbitrary runtimes:

// The `Sse` type is now accessible without the `tokio` feature.
pub struct Sse<S> {
    stream: S,
}

impl<S> Sse<S> {
    pub fn new(stream: S) -> Self { /**/ }

    // The `keep_alive` method now wraps an event `Stream`.
    // The `KeepAliveStream` type implements `Stream` and produces
    // keep-alive events at the specified interval.
    // This method will also require the feature flag.
    #[cfg(feature = "tokio")]
    pub fn keep_alive(self, keep_alive: KeepAlive) -> Sse<KeepAliveStream<S>> {
        Sse {
            stream: KeepAliveStream::new(keep_alive, self.stream),
        }
    }
}

This design preserves the familiar way of using SSE:

use axum::response::sse::{Event, KeepAlive, Sse};

async fn sse_handler() -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
    let stream = /* create the event stream */;

    Sse::new(stream).keep_alive(
        KeepAlive::new()
            .interval(std::time::Duration::from_secs(1))
            .text("keep-alive-text"),
    )
}

Alternatives

As an alternative, we could leave the current SSE implementation as it is and require users to implement their own equivalent for the runtime they are using.

However, this approach requires a significant amount of additional code, much of which is unrelated to the runtime itself (and in some cases, completely unrelated). At the same time, it would be nice to have higher-level support for SSE built into the framework.

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

No branches or pull requests

1 participant