Skip to content

Add pipeline phase visibility via /status and OTel gauge#1000

Merged
kvch merged 8 commits into
xataio:mainfrom
Shaurya2k06:feat/pipeline-phase-status
Jul 16, 2026
Merged

Add pipeline phase visibility via /status and OTel gauge#1000
kvch merged 8 commits into
xataio:mainfrom
Shaurya2k06:feat/pipeline-phase-status

Conversation

@Shaurya2k06

Copy link
Copy Markdown
Contributor

Description

Adds queryable pipeline phase visibility so operators can tell whether a running pgstream process is in the initial snapshot or replication (streaming) phase without scraping logs.

In snapshot_and_replication mode, the only signal today is log order: initial snapshot enabledsnapshot generation completedlogical replication started. pgstream status is a static config/init check against Postgres and has no phase field.

This PR exposes phase via:

  1. GET /status on the existing health server (alongside /health and /ready)
  2. OTel observable gauge pgstream.pipeline.phase

The phase flips to replication when logical replication starts (after successful StartReplication / StartReplicationFromLSN), matching the existing log signal.

Related Issue(s)

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test coverage improvement
  • 🔨 Build/CI changes
  • 🧹 Code cleanup

Changes Made

  • Add internal/phase.Tracker — thread-safe atomic tracker with snapshot and replication phases
  • Extend health server with GET /status and WithPhaseProvider; response includes phase field
  • Wire tracker from run / snapshot commands into health server and stream pipeline
  • Set phase at lifecycle boundaries in postgres, snapshot-only, and kafka listeners:
    • snapshot_and_replication: snapshot at start of snapshotAndListen, replication after StartReplicationFromLSN succeeds
    • replication only: replication after StartReplication succeeds
    • pgstream snapshot: snapshot when snapshot Listen starts
    • Kafka source: replication when kafka Listen starts
  • Register OTel Int64ObservableGauge pgstream.pipeline.phase (value 1 with phase attribute)
  • Document /status in docs/configuration.md and config_template.yaml
  • Document pgstream.pipeline.phase in docs/Observability.md

Out of scope (per issue discussion): enriching CLI pgstream status — it runs as a separate process and cannot observe in-memory pipeline state; slot/LSN heuristics would be unreliable.

Before / After

Signal Before After
GET /status 404 (endpoint did not exist) {"status":"ok","version":"...","phase":"snapshot"|"replication"|""}
pgstream status Static init/config check, no phase Unchanged
OTel metrics No pipeline phase metric pgstream.pipeline.phase{phase="snapshot"|"replication"} = 1
Logs Only signal for phase transitions Unchanged (still emitted)

Testing

  • Unit tests added/updated
    • internal/phase/phase_test.go — tracker get/set, nil-safe
    • internal/health/health_test.go/status handler with/without provider, phase transitions
    • pkg/wal/listener/postgres/wal_pg_listener_test.go — phase flips at StartReplication / StartReplicationFromLSN
    • pkg/stream/phase_metrics_test.goregisterPhaseMetric via OTel ManualReader
  • Integration tests added/updated
    • pkg/stream/integration/phase_status_integration_test.go — polls GET /status through snapshot → replication on a real pg2pg snapshot_and_replication run; verifies post-snapshot insert replicates to target
  • Manual testing performed
    • Integration test exercises live HTTP polling of /status during snapshot and replication (automated equivalent of manual curl)
  • All existing tests pass
    • make test passes
    • Integration test passes locally with OrbStack

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Code is well-commented
  • Documentation updated where necessary

Additional Notes

Operators can query whether a running process is in snapshot or
replication without scraping logs. The phase flips when logical
replication starts, covering all source modes.

Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
Cover registerPhaseMetric with an OTel ManualReader and add an
integration test that polls GET /status through snapshot and
replication during a real pg2pg snapshot_and_replication run.

Signed-off-by: shaurya2k06 <shaurya2k06@gmail.com>
Comment thread cmd/run_cmd.go Outdated
Comment thread cmd/snapshot_cmd.go Outdated
@kvch

kvch commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

You can ignore the coverage failure, but please fix the issues reported by the linter.

@Shaurya2k06
Shaurya2k06 requested a review from kvch July 15, 2026 08:31
Comment thread pkg/stream/phase_metrics.go Outdated
}
// snapshotAndListen already entered the listen loop; only reached on
// clean return (context cancel) or if snapshot path returned early.
return nil

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please explain the reasoning behind this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The old fallthrough was unreachable in the current code path, because snapshotAndListen() always ends by calling listen() , and listen() only returns a non-nil error or ctx.Err(), not nil. So the explicit return nil isn't really a behavior fix, it's mainly about safety, it makes it obvious that once the snapshot path is used, the function should stop there and not continue into the normal replication startup path.It also prevents a future refactor from accidentally making the old fallthrough reachable and then calling StartReplication() twice on the same listener flow.

How do you think this should be dealt with? Again, It's guard-railing/documentation, not a bug fix.

Comment thread pkg/stream/stream_snapshot.go Outdated

@kvch kvch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank your for getting back to the PR. I've posted a few notes.

@Shaurya2k06
Shaurya2k06 requested a review from kvch July 16, 2026 08:11

@kvch kvch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thank you!

@kvch
kvch enabled auto-merge (squash) July 16, 2026 14:51
@kvch
kvch merged commit df12dc3 into xataio:main Jul 16, 2026
7 of 8 checks passed
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.

Add phase visibility for snapshot_and_replication mode

2 participants