Skip to content

feat(event-streams): improve subscribe UX#1534

Open
developerkunal wants to merge 5 commits into
mainfrom
feat/subscribe-improvements
Open

feat(event-streams): improve subscribe UX#1534
developerkunal wants to merge 5 commits into
mainfrom
feat/subscribe-improvements

Conversation

@developerkunal
Copy link
Copy Markdown
Contributor

@developerkunal developerkunal commented May 28, 2026

🔧 Changes

Improves the auth0 event-streams subscribe UX so live event inspection is easier to read, easier to interrupt, and easier to resume, and keeps long-lived sessions alive across the server's periodic connection rotations.

Discoverability

  • --list-event-types prints every value accepted by --event-type and exits without opening a subscription.
  • Invalid --event-type values are now collected up front and reported in a single error listing every bad value, instead of bailing on the first. The error points at --list-event-types for the full list, and the SDK's internal Go type name no longer leaks into user output.

Reconnect behavior

  • The server rotates long-lived SSE connections every few minutes. Previously this exhausted the SDK's lifetime reconnect cap and the session silently ended. The command now owns reconnection via a CLI-level resume loop that re-subscribes from the last cursor, so the session stays continuous and no events are missed.
  • Reconnect delay is exponential backoff with full jitter, accrued only on consecutive zero-progress failures; any forward progress resets it, so healthy rotations reconnect instantly and silently. The server-advertised SSE retry: directive is honored as a floor, and a 1s minimum interval between attempts prevents a flapping connection from spinning in a tight loop.
  • --no-reconnect exits cleanly when the connection ends instead of resuming.
  • --max-reconnects N caps consecutive failed reconnect attempts before giving up (0 = retry indefinitely while progress is being made). Mutually exclusive with --no-reconnect.
  • Ctrl+C cancels via context so the disconnect summary always prints.

Output cleanups

  • connection_timeout frames (a protocol artifact emitted right before the server drops the SSE connection) are filtered up front, so the rendered output, --json / --json-compact, and the --output-file capture all stay consistent and free of reconnect noise.
  • Server-emitted error events (rate limits, auth, etc.) render on their own row, are tracked in a separate Errors: counter in the summary, and no longer pollute per-type event counts.
  • The disconnect summary now reports session duration, an Errors: line when non-zero, and groups per-type counts under a By type: heading, sorted by count desc with aligned columns.
  • Event rows align: type and source pad to fixed widths before ANSI coloring so escape codes don't break visual alignment. Event IDs and error messages stay full-length so nothing forensic is truncated.
  • The resume hint prints as a single line so the cursor is easy to copy.

Bumps

  • github.com/auth0/go-auth0/v2: v2.11.0 → v2.12.0.

📚 References

None.

🔬 Testing

Unit tests added in internal/cli/event_streams_subscribe_test.go covering the pure helpers:

  • summarizeEvent for heartbeat, error, connection_timeout, and concrete-event envelope variants.
  • padRight for short, equal, long, and empty inputs.
  • shortOffset for short, boundary, and long cursor truncation.
  • colorForEventType confirms the original type string survives the color wrap for every suffix branch plus error and unknown.
  • invalidEventTypesError covers single-value and multi-value cases, plus a guard that the SDK's internal type name never leaks into user output.
  • reconnectBackoff confirms an immediate reconnect on a healthy rotation, that jittered delays stay within their exponential ceiling and never exceed the 30s cap, and that the server retry: directive acts as a floor.

Run with:

go test ./internal/cli/ -run 'TestSummarizeEvent|TestPadRight|TestShortOffset|TestColorForEventType|TestInvalidEventTypesError|TestReconnectBackoff'

Manual end-to-end testing against a live tenant:

  • auth0 event-streams subscribe left running across multiple server connection rotations to confirm the session stays continuous with no event loss and no reconnect noise, then Ctrl+C to confirm the summary shows duration, event counts, errors when any, heartbeats, the By type: block, and a readable resume hint.
  • auth0 event-streams subscribe --list-event-types to confirm the full list prints and the command exits.
  • auth0 event-streams subscribe --event-type bad.value --event-type also.bad to confirm both bad values are reported in one error.
  • auth0 event-streams subscribe --no-reconnect and --max-reconnects 1 to confirm both flags are accepted and mutually exclusive.

📝 Checklist

  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

…12.0

Adds --no-reconnect / --max-reconnects flags wired to the new
option.WithoutStreamReconnection / WithMaxStreamReconnectAttempts in
go-auth0 v2.12.0, and --list-event-types to discover valid --event-type
values. Filters connection_timeout error frames up front so JSON,
output file, and rendered output all skip the SDK's reconnect
artifacts. Tracks server-emitted error events separately from per-type
counts and surfaces them in the disconnect summary alongside session
duration. Aligns rendered event rows with fixed-width columns, prints
a more readable resume hint that wraps cleanly on long cursors, and
returns a single error reporting all invalid --event-type values at
once instead of bailing on the first.
@developerkunal developerkunal requested a review from a team as a code owner May 28, 2026 14:00
Comment thread internal/cli/event_streams_subscribe.go Outdated
Comment on lines +290 to +292
cli.renderer.Infof("Resume from cursor %s:", ansi.Faint(shortOffset(lastOffset)))
cli.renderer.Output(" " + ansi.Cyan("auth0 event-streams subscribe --from \\"))
cli.renderer.Output(" " + ansi.Cyan(lastOffset))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are adding lastOffSet twice in the output.. one in the info and another in the output command.. Can this be reverted..?

duedares-rvj
duedares-rvj previously approved these changes May 29, 2026
… rotations

The server rotates long-lived SSE connections every few minutes, which
previously exhausted the SDK's lifetime reconnect cap and silently ended
the session. Replace SDK-internal reconnection with a CLI-level resume
loop that re-subscribes from the last cursor, so the session stays
continuous and no events are missed.

Backoff uses exponential delay with full jitter and only accrues on
consecutive zero-progress failures; any forward progress resets it so
healthy rotations reconnect instantly and silently. The server-advertised
SSE retry directive is honored as a floor. --max-reconnects now caps
consecutive failed attempts (0 = unlimited while progress is made), and
Ctrl+C cancels via context so the summary always prints.

Also collapse the duplicated resume hint into a single line.
A connection that flaps (delivers a frame then dies immediately) counts as
forward progress and resets the backoff, which could spin in a tight
reconnect loop. Enforce a 1s floor between attempts based on how long the
session actually lasted, so healthy long-lived sessions are unaffected but
flapping connections are paced.
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.

3 participants