SQLStreams

the messaging platform that is just Postgres

You last visited on 9999-99-99 Show what's new since then

Where a New Group Starts

Edit this page
Posted: 2026-09-09 · Report this thread
brandon Site Admin brandon profile Posts: 677

A new consumer group starts at the beginning of retained history unless its config’s Start says otherwise, and sqlstreams.Head() says “the head of the log”: the group sees only messages produced after it was registered. The position is used once, when Register creates the group’s cursor row; an existing group keeps its position no matter what the config says on a later Register.

scoring, err := client.Stream[OrderPlaced]("orders.placed").Consumer("fraud-scoring").Register(ctx,
	&sqlstreams.ConsumerConfig{
		Start: sqlstreams.Head(),
	})
if err != nil {
	return err
}
return scoring.Consume(ctx, scoreOrder, nil)

To read retained history, leave Start unset or use sqlstreams.Beginning(). Moving an existing group is a different operation; the rewind proposal is not shipped API.

Choose the initial position

ValueNew group reads
sqlstreams.Beginning() (default)retained history, then live traffic
sqlstreams.Head()messages with ids above the visible head at registration

Both construct sqlstreams.CursorPosition. The position only applies when registration creates the cursor; it does not reset an existing group.

Worked case

orders.placed (stream id 1) has been live for a year and message_log_1 holds ids 1 through 1204318. A fraud-scoring service is added today and only needs to score new orders.

Register with Start: sqlstreams.Head() creates the cursor row at the head instead of at 0:

SELECT
    consumer_group_id,
    claimed,
    committed,
    settled_head
FROM sqlstreams.consumer_group_cursor_1
WHERE consumer_group_id = 7;
--  consumer_group_id | claimed | committed | settled_head
--  7                 | 1204318 | 1204318   | 1204318

The next produce is id 1204319. The group’s first claim is the range (1204318, 1204319] and the handler sees exactly that order. The year behind it is never read, and because committed already sits at the head, this group does not prevent retention from deleting that older history. If it falls behind later, it can still delay future cleanup.

The register log line carries the position, so a group that started at the head says so once:

consumer group registered (created) group=fraud-scoring stream_id=1 group_id=7 committed=1204318

What “after” means

A produce can allocate an id before group registration and commit after it. If that id is at or below the recorded head, the new group skips it. Register the group before producers start when it must receive traffic around its startup. See the registration boundary for a concrete transaction example and the cursor columns involved.

Existing groups and recovery

Changing Start on an existing fraud-scoring group leaves its cursor in place. The creation log shown above only appears when the cursor is created. Inspect the stored position to verify the result.

For a separate read of history, use a fresh group with the intended handler. Deleting and recreating a group also deletes its delivery state and is a destructive operation; see Consumer for the guards and Replaying History for the recovery workflow. Starting from a chosen id or timestamp is still proposed.