mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
progress_bus.subscribe() eagerly enters the pub/sub subscription (opening a Redis connection + starting a listener thread) BEFORE the SSE generator exists, so the subscribe completes before the Celery advance can publish. But the only close() lived in the generator's finally -- which Python does not run if the generator is never started. A streaming Response dropped before its first frame (client aborted, or an after_request/teardown error) therefore leaked the connection + thread until process restart. stream_advance_frames now returns a small _ClosingFrameStream wrapper whose close() closes the subscription directly (idempotent); the WSGI server calls close() on the response iterable even on early disconnect, so cleanup fires regardless of iteration. The inner generator keeps its own finally for the iterated/disconnect paths, so this is strictly additive -- no happy-path change. All seven call sites get it unchanged. Adds a regression test (never-iterated stream -> close() -> subscription closed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>