Skip to content

fix(observability): bound websocket trace spans#3

Open
Ankcorn wants to merge 1 commit into
stack/pr-1860-currentfrom
tankcorn/bound-websocket-trace-spans
Open

fix(observability): bound websocket trace spans#3
Ankcorn wants to merge 1 commit into
stack/pr-1860-currentfrom
tankcorn/bound-websocket-trace-spans

Conversation

@Ankcorn

@Ankcorn Ankcorn commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Why

A canceled or disconnected hibernatable WebSocket turn can end its Worker invocation before JavaScript stream finalizers run. This left exactly five custom spans open: chat_interaction, chat_turn, invoke_agent, persist_chat_result, and the active chat span.

What

The tracer now owns bounded span lifetimes. Call sites declaratively choose one of two policies:

  • finish after a matching child span opens
  • finish when a callback hands off asynchronous work

There are no finish() callbacks to thread through the chat lifecycle. The tracer keeps the finished span's async context active, preserving the existing hierarchy:

chat_interaction
└── chat_turn
    ├── invoke_agent
    │   └── chat
    └── persist_chat_result

These policies apply only to ws-chat; RPC and alarm turns retain full-stream span lifetimes and attributes.

Evidence

A local Service Trace Worker reproduced both explicit cancellation and hard disconnects:

before: 65 SpanOpen / 60 SpanClose
 after: 65 SpanOpen / 65 SpanClose

Completed WebSocket turns remain balanced and raw parent IDs remain unchanged. Agents tracing tests and all AI Chat (646) and Think (910) Worker tests pass.

Stacked on cloudflare#1860.

@Ankcorn
Ankcorn force-pushed the tankcorn/bound-websocket-trace-spans branch from e8bb6e6 to 7cfbea0 Compare July 16, 2026 11:11
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

Successfully merging this pull request may close these issues.

1 participant