Skip to content

SSE + interceptors: producer Observable is subscribed then unsubscribed in the same tick when client disconnects during async handler setup #17352

Description

@samjoffe

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

Follow up from #17128 and #17190

For an SSE route behind interceptors whose handler returns Promise, if the client disconnects while that promise is still resolving, @nestjs/core (since ~11.1.25's fix for #17190) subscribes the resolved Observable and then unsubscribes it synchronously in the same tick (InterceptorsConsumer.transformDeferred path: the outer SSE subscription is already closed, so the deferred producer is subscribed and immediately torn down). The producer's setup function runs but its teardown fires before it can emit anything.

This makes the #17190 fix insufficient for real workloads: our producer streams an LLM generation and mirrors events into Redis so a reconnecting client can resume. A disconnect during the async setup window kills the generation, so there is nothing to resume. Observing "the Observable got subscribed" is not enough — it must be allowed to run.

Minimum reproduction code

https://pastebin.com/pKZtVSfC

Steps to reproduce

Client: open the request, destroy the socket ~20ms in (during the 80ms setup). Result: producer teardown runs in the same tick as subscribe; nothing is emitted.

Expected behavior

Expected behavior

Either (a) don't subscribe a producer whose consumer is already gone (pre-11.1.25 behavior on the non-interceptor path), or (b) if the intent of the #17190 fix is that the producer should run, don't immediately unsubscribe it. Same-tick subscribe→unsubscribe is the worst of both: side effects start and are instantly aborted.

NestJS version

11.1.28

Packages versions

11.1.28

Node.js version

No response

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs triageThis issue has not been looked into

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions