fix(sink,tui): restore session init callback, trace ID was never shown - #861
Open
maoueh wants to merge 1 commit into
Open
fix(sink,tui): restore session init callback, trace ID was never shown#861maoueh wants to merge 1 commit into
maoueh wants to merge 1 commit into
Conversation
The "Feature/request v3" change (7908100, released in v1.17.0) retyped `SinkerSessionInitHandler.HandleSessionInit` to take a `rpc/v3.Request` but left `fullSinkerHandlers` and both `NewSinkerFullHandlers*` constructors on `rpc/v2`. The concrete type stopped satisfying its own interface, so the sinker's `handler.(SinkerSessionInitHandler)` assertion silently stopped matching and the session callback was never invoked. Consequences, all from that single root cause: - `substreams run` in TUI mode stayed on `Connecting...` forever, never displaying the trace ID, and hid the whole per-stage progress section. - `substreams run` in non-TUI modes stopped printing the `TraceID:`, `Server HEAD block:` and blocks-to-process summary lines. A second, independent bug sat behind the first: the bubbletea model matched `*rpc.Response_Session` while the UI sends a `*rpc.SessionInit`, so even a firing callback would not have updated the view. `SinkerErrorHandler` was dead for the same reason (`*rpc.Error` vs `error`). Fixing it lets the TUI fall back to `Connecting...` and pick up the new trace ID when the sinker retries a severed stream, instead of advertising a stale one. Since these hooks are reached through a type assertion, a signature that drifts turns them into dead code with no compile error. Added compile-time interface assertions on `fullSinkerHandlers` to close that hole permanently — they are what surfaced the session-init bug. Also guards `barmode` against a divide by zero: bar mode was unreachable while the connected view never rendered, and `BarSize` is 0 until the first `tea.WindowSizeMsg` arrives. BREAKING: the `handleSessionInit` and `handleError` callbacks passed to `NewSinkerFullHandlers`/`NewSinkerFullHandlersWithPartial` change type. Callers passing nil are unaffected; callers passing a callback get a compile error and have had a dead callback since v1.17.0 regardless.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
substreams runnever displayed the Trace ID while backprocessing, sitting onConnecting...indefinitely:Root cause
Commit 7908100 ("Feature/request v3", #690, first released in v1.17.0, 2025-10-21) touched
sink/types.goin two hunks only: it added the v3 import and retyped the interface method.The
fullSinkerHandlersstruct field, itsHandleSessionInitmethod and bothNewSinkerFullHandlers*constructor signatures were left onrpc/v2in that same file. The concrete type stopped satisfying its own interface, so the sinker'shandler.(SinkerSessionInitHandler)assertion silently stopped matching and the session callback has never been invoked since. It compiled cleanly the whole time because nothing asserted the two agreed.Two consequences, one cause:
.Connected; theLongest-running jobsblock sits outside that gate, which is exactly why the reported output showed running jobs under aConnecting...header.--output json,jsonl, ...) — theTraceID:,Server HEAD block:and blocks-to-process summary lines silently stopped printing.A second, independent bug sat behind the first: the bubbletea model matched
*rpc.Response_Sessionwhile the UI sends a*rpc.SessionInit. Even a firing callback would not have updated the view. Both had to go.Changes
req.Modules→req.Package.Modules.SinkerErrorHandler, dead for the identical reason (*rpc.Errorvserror). Wired into the TUI so a retried stream falls back toConnecting...and picks up the new trace ID, instead of advertising a stale one.fullSinkerHandlersfor all five optional interfaces. These hooks are reached by type assertion, so signature drift turns them into dead code with no compiler complaint — this is what surfaced the session-init bug within seconds of being added.barmodeagainst a divide by zero. Bar mode (m) was unreachable while the connected view never rendered;BarSizeis 0 until the firsttea.WindowSizeMsg, so pressingmin that window collapsed the entire view into a template error.Breaking change
handleSessionInitandhandleErrorpassed toNewSinkerFullHandlers/NewSinkerFullHandlersWithPartialchange type.Callers passing
nilare unaffected. Callers passing a callback get a compile error pointing at the exact line — and have had a silently dead callback since v1.17.0, so no behavior can depend on it today. Callers implementingSinkerSessionInitHandlerdirectly on their own type already wrote the v3 signature and are unaffected; moving the interface back to v2 instead would have broken those consumers silently, which is why the fix goes this direction.I could not verify how the external sinks (
substreams-sink-sql,-kv,-files, ...) call these constructors — separate repos. The compile error will surface it at their next bump.Verification
go build ./...and the fullgo test ./...suite pass. Each fix has a test that was confirmed to fail without it:TestModelUpdate_SessionInit— reproduces the exact stuck-on-Connecting...output.TestModelUpdate_ReconnectRefreshesTraceID— stale trace ID across a retry.TestModelView_ConnectedBarModeEdgeCases— confirmedinteger divide by zerowithout the guard.TestNewSinkerFullHandlers_SatisfiesOptionalInterfaces/TestFullSinkerHandlers_ForwardsSessionInitAndError— asserts on what the constructors actually return, since the compile-time assertions only cover the concrete type.