Skip to content

deno: Deno.serve does not record request sessions #25495

Open

Description

@isaacs

denoHttpIntegration records a request session for each incoming node:http request (#22888 turned this on). denoServeIntegration does not record sessions at all. Most Deno apps use Deno.serve, so release health for those apps shows no request sessions and no crash-free rate.

#25492 gives denoServeIntegration the other incoming request options from denoHttpIntegration. It leaves out sessions and sessionFlushingDelayMS, because they need more than an option.

Proposed options

Use the same names, defaults and behavior as denoHttpIntegration.

Option Type Default Notes
sessions boolean true Record a request session for each incoming Deno.serve request.
sessionFlushingDelayMS number 60000 Time until the SDK sends the session aggregate.

Why this is not a plain option

The shared helper recordRequestSession in @sentry/core/server does most of the work. It marks the request as a session on the isolation scope, counts it in a per-minute bucket when the request ends, and sends the aggregate on a timer or on client.flush(). DenoClient extends ServerRuntimeClient, which already sets the session status to errored or crashed when the SDK captures an exception during the request.

The problem is how the helper knows that a request ended. It takes a node:http response and waits for its close event:

recordRequestSession(client, { requestIsolationScope, response, sessionFlushingDelayMS });
// inside: response.once('close', () => { /* count the session */ });

Deno.serve has no response object with events. The handler returns a web Response, and a streamed body can finish long after the handler returns.

Suggested approach

  1. Change recordRequestSession so it does not need a node:http response. For example, split it into a start step that returns an end() function. Node and denoHttpIntegration call end()from the response close event, so their behavior does not change.
  2. In packages/deno/src/wrap-deno-request-handler.ts, start the session for each request when sessions is on. Call end() when the response finishes:
  3. Sessions do not depend on tracing. They must work when the SDK skips the span, for example with spans: false, ignoreIncomingRequests, a static asset, or tracing turned off. Today streamResponse takes a span, so the stream end needs a code path that works without one.

A fake response object that emits close would also work, but it hides the real contract and is easy to break.

Decisions needed

  • OPTIONS and HEAD requests. The wrapper returns early for these methods. Core's node:http code records a session for every request, including these. Match Node unless there is a reason not to.
  • Changelog. With sessions defaulting to true, Deno.serve apps start to send session aggregates after an upgrade. This needs a note.

Tests

Add tests to packages/deno/test/deno-serve.test.ts. Use a test transport and call client.flush()to send the aggregate.

  • A successful request counts as exited.
  • A handled captureException in the handler counts as errored.
  • A thrown error counts as crashed.
  • sessions: false sends no session.
  • A streamed response counts only after the stream finishes.
  • Sessions are recorded when tracing is off and when the span is skipped.

Related

  • Bun.serve (bunServerIntegration) also records no request sessions. The same recordRequestSession change would help there.

Activity

  1. added
    javascriptPull requests that update javascript code
    on Oct 18, 2026
  2. linear-code commented on Oct 18, 2026

    @linear-code
  3. self-assigned this
    on Oct 18, 2026
  4. added a commit that references this issue on Oct 19, 2026
    23896e3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

javascriptPull requests that update javascript code

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions