Make all hardcoded timing/buffer constants configurable with good defaults #129

Closed
opened 2026-03-01 10:35:41 +00:00 by ash · 0 comments
Owner

Problem

Several components have hardcoded timing and buffer constants that should be configurable:

ChangeNotifier (changenotifier.go)

  • changeNotifierBufferSize = 64 — subscriber channel buffer
  • Missing: SSE polling fallback interval (currently no fallback at all — dropped notifications = permanently stale UI)

PGChangeRelay (pgstore/change_relay.go)

  • changeReconnectDelay = 1s — reconnection delay after connection loss
  • Broadcast timeout 2s — PG NOTIFY timeout

ChannelEventBus (eventbus_channel.go)

  • channelBufSize = 256 — subscriber channel buffer

Solution

ChangeNotifier

Add options pattern:

type ChangeNotifierOption func(*ChangeNotifier)

func WithBufferSize(size int) ChangeNotifierOption
func WithFallbackPoll(interval time.Duration) ChangeNotifierOption // NEW: periodic re-notify as safety net

The fallback poll is critical: if a notification is dropped (buffer full), the SSE handler currently has NO way to recover. Add an optional ticker that fires a synthetic change so SSE handlers re-read from DB. Default: 5s. Set to 0 to disable.

Alternatively, add a SubscribeWithPoll(projection, interval) that returns a channel that also receives periodic ticks — letting each subscriber choose their own fallback interval.

PGChangeRelay

Add to constructor or options:

type PGChangeRelayOption func(*PGChangeRelay)

func WithReconnectDelay(d time.Duration) PGChangeRelayOption
func WithBroadcastTimeout(d time.Duration) PGChangeRelayOption

Defaults: reconnect 1s, broadcast 2s.

ChannelEventBus

Add option:

func WithChannelBufferSize(size int) ChannelEventBusOption

Default: 256.

Requirements

  • All current constants become defaults
  • Options pattern for configuration (consistent with rest of eskit)
  • Godoc on every option explaining what it does and the default value
  • Tests for custom values
  • Benchmarks for any hot-path changes
  • The SSE fallback poll is the most important addition here — it turns "permanently stale" into "at most N seconds stale"

Related: subscription.Config already does this correctly — PollInterval, RetryBaseDelay, etc. are all configurable with defaults. Match that pattern.

## Problem Several components have hardcoded timing and buffer constants that should be configurable: ### ChangeNotifier (`changenotifier.go`) - `changeNotifierBufferSize = 64` — subscriber channel buffer - **Missing:** SSE polling fallback interval (currently no fallback at all — dropped notifications = permanently stale UI) ### PGChangeRelay (`pgstore/change_relay.go`) - `changeReconnectDelay = 1s` — reconnection delay after connection loss - Broadcast timeout `2s` — PG NOTIFY timeout ### ChannelEventBus (`eventbus_channel.go`) - `channelBufSize = 256` — subscriber channel buffer ## Solution ### ChangeNotifier Add options pattern: ```go type ChangeNotifierOption func(*ChangeNotifier) func WithBufferSize(size int) ChangeNotifierOption func WithFallbackPoll(interval time.Duration) ChangeNotifierOption // NEW: periodic re-notify as safety net ``` The fallback poll is critical: if a notification is dropped (buffer full), the SSE handler currently has NO way to recover. Add an optional ticker that fires a synthetic change so SSE handlers re-read from DB. Default: 5s. Set to 0 to disable. Alternatively, add a `SubscribeWithPoll(projection, interval)` that returns a channel that also receives periodic ticks — letting each subscriber choose their own fallback interval. ### PGChangeRelay Add to constructor or options: ```go type PGChangeRelayOption func(*PGChangeRelay) func WithReconnectDelay(d time.Duration) PGChangeRelayOption func WithBroadcastTimeout(d time.Duration) PGChangeRelayOption ``` Defaults: reconnect 1s, broadcast 2s. ### ChannelEventBus Add option: ```go func WithChannelBufferSize(size int) ChannelEventBusOption ``` Default: 256. ## Requirements - All current constants become defaults - Options pattern for configuration (consistent with rest of eskit) - Godoc on every option explaining what it does and the default value - Tests for custom values - Benchmarks for any hot-path changes - The SSE fallback poll is the most important addition here — it turns "permanently stale" into "at most N seconds stale" Related: subscription.Config already does this correctly — PollInterval, RetryBaseDelay, etc. are all configurable with defaults. Match that pattern.
ash closed this issue 2026-03-01 10:41:54 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ash/eskit#129
No description provided.