Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions pgcopydb-helpers/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,26 +308,21 @@ Cleans up pgcopydb replication artifacts on both source and target databases.

#### `stop-cdc.sh`

Sets the CDC endpoint LSN so pgcopydb stops streaming after reaching a specific position. This is how you initiate cutover.
Sets the CDC endpoint LSN so pgcopydb stops streaming after reaching a specific position. This is how you initiate cutover. The script fetches the current WAL LSN from the source automatically, displays it, and prompts for confirmation before writing it to the sentinel.

```bash
# Get the current source LSN
psql "$PGCOPYDB_SOURCE_PGURI" -t -A -c "SELECT pg_current_wal_lsn();"

# Set the endpoint
~/stop-cdc.sh 41EBA/7C7A1AD8
MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh 41EBA/7C7A1AD8 # explicit dir
~/stop-cdc.sh
MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh # explicit dir
```

**Cutover procedure:**
1. Stop writes to the source database (maintenance mode, read-only, etc.)
2. Get the current WAL LSN from the source
3. Run `stop-cdc.sh` with that LSN
4. Wait for `check-cdc-status.sh` to show the apply LSN has reached the endpoint
5. pgcopydb exits cleanly
6. Verify data on the target
7. Switch application to the target
8. Run `drop-replication-slots.sh` to clean up
2. Run `stop-cdc.sh` — it fetches the current WAL LSN, shows it, and asks you to confirm
3. Wait for `check-cdc-status.sh` to show the apply LSN has reached the endpoint
4. pgcopydb exits cleanly
5. Verify data on the target
6. Switch application to the target
7. Run `drop-replication-slots.sh` to clean up

**Requires:** `PGCOPYDB_SOURCE_PGURI`, `PGCOPYDB_TARGET_PGURI`

Expand Down Expand Up @@ -430,7 +425,7 @@ sqlite3 ~/migration_*/schema/filter.db \

3. CUTOVER (when CDC is caught up)
- Stop writes to source
- Run ~/stop-cdc.sh <LSN> to set the endpoint
- Run ~/stop-cdc.sh to set the endpoint
- Wait for pgcopydb to finish applying and exit
- Verify data on target
- Switch application to target
Expand Down
12 changes: 3 additions & 9 deletions pgcopydb-helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,11 @@ When `check-cdc-status.sh` reports **"CDC IS CAUGHT UP"** (apply backlog < 100 M

1. **Stop writes** to the source database (maintenance mode, read-only, connection drain, etc.).

2. **Get the current WAL position** on the source:
2. **Set the CDC endpoint** — the script fetches the current WAL LSN from the source, displays it, and asks for confirmation before applying:

```bash
psql "$PGCOPYDB_SOURCE_PGURI" -t -A -c "SELECT pg_current_wal_lsn();"
```

3. **Set the CDC endpoint** so pgcopydb stops after reaching that position:

```bash
~/stop-cdc.sh <LSN>
MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh <LSN> # explicit dir
~/stop-cdc.sh
MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh # explicit dir
```

4. **Wait** for pgcopydb to apply all remaining changes and exit. Monitor with `check-cdc-status.sh`.
Expand Down
34 changes: 20 additions & 14 deletions pgcopydb-helpers/stop-cdc.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/bin/bash

# Usage: ~/stop-cdc.sh <LSN>
# Example: ~/stop-cdc.sh 41EBA/7C7A1AD8
# Example: MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh 41EBA/7C7A1AD8
# Usage: ~/stop-cdc.sh
# Example: MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS ~/stop-cdc.sh
#
# Sets the CDC endpos sentinel so pgcopydb stops streaming
# after reaching the given LSN. Uses MIGRATION_DIR env var if set,
# Fetches the current WAL LSN from the source, asks for confirmation,
# then sets the CDC endpos sentinel so pgcopydb stops streaming after
# reaching that LSN. Uses MIGRATION_DIR env var if set,
# otherwise the most recent ~/migration_*/ directory.
# Use the sqlite3 method (more reliable than the pgcopydb CLI sentinel command).

Expand All @@ -23,23 +23,29 @@ if [ -z "${PGCOPYDB_SOURCE_PGURI:-}" ] || [ -z "${PGCOPYDB_TARGET_PGURI:-}" ]; t
fi
# --- loaded ---

if [ -z "${1:-}" ]; then
echo "Usage: $0 <LSN>"
echo "Example: $0 41EBA/7C7A1AD8"
echo ""
echo "Get current source LSN with:"
echo " psql \"\$PGCOPYDB_SOURCE_PGURI\" -t -A -c \"SELECT pg_current_wal_lsn();\""
echo "Fetching current WAL LSN from source..."
ENDPOS_LSN=$(psql "$PGCOPYDB_SOURCE_PGURI" -t -A -c "SELECT pg_current_wal_lsn();" 2>&1)
if [ $? -ne 0 ] || [ -z "$ENDPOS_LSN" ]; then
echo "ERROR: Failed to fetch LSN from source database:"
echo " $ENDPOS_LSN"
exit 1
fi

ENDPOS_LSN="$1"
echo ""
echo "Current source LSN: $ENDPOS_LSN"
echo ""
read -r -p "Stop CDC at this LSN? [y/N] " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
echo "Aborted."
exit 0
fi

# Find the most recent migration directory
MIGRATION_DIR="${MIGRATION_DIR:-$(ls -dt ~/migration_*/ 2>/dev/null | head -1 || true)}"

if [ -z "$MIGRATION_DIR" ] || [ ! -d "$MIGRATION_DIR" ]; then
echo "ERROR: No migration directory found. Pass the path as second argument:"
echo " $0 <LSN> ~/migration_YYYYMMDD-HHMMSS"
echo "ERROR: No migration directory found. Set MIGRATION_DIR explicitly:"
echo " MIGRATION_DIR=~/migration_YYYYMMDD-HHMMSS $0"
exit 1
fi

Expand Down