simple-web-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit d4a353f8d326e863fede66c19b068dbe222bce18
parent 151a4d25eb0556ee8495868e0ff5abd529c7b565
Author: Silas Brack <silasbrack@gmail.com>
Date:   Thu, 11 Jun 2026 14:55:03 +0200

fix: add X-Accel-Buffering header to SSE responses for nginx

Nginx buffers proxy responses by default, which prevents SSE
events from reaching the client in real-time. The /api/ location
had explicit proxy_buffering=off but the / location (serving the
app) did not. Adding X-Accel-Buffering: no to all SSE responses
tells nginx to disable buffering per-response.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
Msrc/handlers/story.rs | 13+++++++++----
Msrc/sse.rs | 1+
2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/handlers/story.rs b/src/handlers/story.rs @@ -3,7 +3,7 @@ use std::convert::Infallible; use askama::Template; use axum::{ extract::{Path, State}, - response::{Html, Redirect, sse::{Event, Sse}}, + response::{Html, IntoResponse, Redirect, Response, sse::{Event, Sse}}, Form, }; use axum_extra::extract::cookie::CookieJar; @@ -407,7 +407,7 @@ pub async fn comments_stream( State(state): State<AppState>, jar: CookieJar, Path(story_id): Path<i64>, -) -> Sse<impl tokio_stream::Stream<Item = Result<Event, Infallible>>> { +) -> Response { let tokens = get_tokens_from_cookies(&jar); let (tx, rx) = tokio::sync::mpsc::channel::<Result<Event, Infallible>>(10); @@ -492,10 +492,15 @@ pub async fn comments_stream( }); let stream = tokio_stream::wrappers::ReceiverStream::new(rx); - Sse::new(stream).keep_alive( + let sse = Sse::new(stream).keep_alive( axum::response::sse::KeepAlive::new() .interval(std::time::Duration::from_secs(30)), - ) + ); + let mut response = sse.into_response(); + response + .headers_mut() + .insert("X-Accel-Buffering", "no".parse().unwrap()); + response } fn render_edit_error(story_id: i64, form: &EditForm, all_tags: &[trailbase::Category], error: &str) -> Html<String> { diff --git a/src/sse.rs b/src/sse.rs @@ -26,6 +26,7 @@ fn patch_elements_with_options( .status(StatusCode::OK) .header(header::CONTENT_TYPE, "text/event-stream") .header(header::CACHE_CONTROL, "no-cache") + .header("X-Accel-Buffering", "no") .body(Body::from(body)) .unwrap() }