-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Handle invalidated replication slot which is an unrecoverable f…
…ailure state (#106) Here we add handling of the fatal error caused by replication slot invalidation. Since there's no recovery procedure that Electric can do in this case, it simply halts execution. The user should resolve the issue in their Postgres database before restarting Electric. Crucially, the only way to resolve this problem is to delete the replication slot and reconfigure the database cluster. A legitimate question arises: will Electric be able to recover the state of the logical replication stream after it restarts and is forced to create a new replication slot? This question remains unanswered for now. Later I'll be sharing a document that outlines the problem in an even broader context. The other change here is a basic setup to write and run integration tests using Lux.
- Loading branch information
Showing
10 changed files
with
247 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
name: Integration Tests | ||
|
||
on: | ||
push: | ||
branches: ['main'] | ||
pull_request: | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
build: | ||
name: Build and test | ||
runs-on: ubuntu-latest | ||
defaults: | ||
run: | ||
working-directory: integration-tests | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: erlef/setup-beam@v1 | ||
with: | ||
version-type: strict | ||
version-file: '.tool-versions' | ||
- name: Restore dependencies cache | ||
uses: actions/cache@v3 | ||
with: | ||
path: packages/sync-service/deps | ||
key: ${{ runner.os }}-mix-${{ hashFiles('packages/sync-service/mix.lock') }} | ||
restore-keys: ${{ runner.os }}-mix- | ||
- name: Restore compiled code | ||
uses: actions/cache/restore@v4 | ||
with: | ||
path: | | ||
packages/sync-service/_build/*/lib | ||
!packages/sync-service/_build/*/lib/electric | ||
key: ${{ runner.os }}-build-test-${{ hashFiles('packages/sync-service/mix.lock') }} | ||
- name: Install dependencies | ||
run: mix deps.get && mix deps.compile | ||
working-directory: packages/sync-service | ||
- name: Save compiled code | ||
uses: actions/cache/save@v4 | ||
with: | ||
path: | | ||
packages/sync-service/_build/*/lib | ||
!packages/sync-service/_build/*/lib/electric | ||
key: ${{ runner.os }}-build-test-${{ hashFiles('packages/sync-service/mix.lock') }} | ||
- name: Compile | ||
run: mix compile --force --all-warnings --warnings-as-errors | ||
working-directory: packages/sync-service | ||
- name: Setup lux | ||
run: make | ||
- name: Run integration tests | ||
run: ./run.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
LUX_BIN="$SCRIPT_DIR/lux/bin/lux" | ||
|
||
lux: | ||
git clone https://github.com/electric-sql/lux.git && \ | ||
cd lux && \ | ||
git checkout otp-27 && \ | ||
autoconf && \ | ||
./configure && \ | ||
make |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Integration tests | ||
|
||
We're using [lux](https://github.com/electric-sql/lux/tree/otp-27) to run integration tests that require setting up and orchestrating multiple components. | ||
|
||
To prepare your dev machine for running these tests, run `make` once. | ||
|
||
To execute all tests, run `./run.sh`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) | ||
|
||
cd "$SCRIPT_DIR"/../packages/sync-service | ||
iex -S mix |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) | ||
|
||
LUX_BIN="$SCRIPT_DIR/lux/bin/lux" | ||
LUX="$LUX_BIN --multiplier=${TIMEOUT_MULTIPLIER:-1000}" | ||
|
||
$LUX ${@:-tests/*.lux} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
[doc Verify handling of invalidated replication slot while Electric is running] | ||
|
||
[include replication-slot-invalidation.luxinc] | ||
|
||
[global pg_container_name=replication-slot-invalidated-while-running__pg] | ||
|
||
[my invalidated_slot_error= | ||
""" | ||
[error] GenServer Electric.ConnectionManager terminating | ||
** (Postgrex.Error) ERROR 55000 (object_not_in_prerequisite_state) cannot read from logical replication slot "electric_slot" | ||
|
||
This slot has been invalidated because it exceeded the maximum reserved size. | ||
"""] | ||
|
||
### | ||
|
||
## Start a new Postgres cluster configured for easy replication slot invalidation. | ||
[invoke setup_pg \ | ||
"--wal-segsize=1" \ | ||
"-c max_slot_wal_keep_size=1MB -c max_wal_size=2MB"] | ||
|
||
## Start the sync service. | ||
[invoke setup_electric] | ||
|
||
[shell electric] | ||
??[info] Starting replication from postgres | ||
|
||
# Reset the failure pattern because we'll be matching on an error. | ||
- | ||
|
||
## Seed the database with enough data to exceed max_wal_size and force a checkpoint that | ||
## will invalidate the replication slot. | ||
[invoke seed_pg] | ||
|
||
## Confirm slot invalidation in Postgres. | ||
[shell pg] | ||
?invalidating slot "electric_slot" because its restart_lsn \d+/\d+ exceeds max_slot_wal_keep_size | ||
|
||
## Observe the fatal connection error. | ||
[shell electric] | ||
??$invalidated_slot_error | ||
|
||
# Confirm Electric process exit. | ||
??$PS1 | ||
|
||
## Start the sync service once again to verify that it crashes due to the invalidated slot error. | ||
[invoke setup_electric] | ||
|
||
[shell electric] | ||
??[info] Starting replication from postgres | ||
- | ||
??$invalidated_slot_error | ||
??$PS1 | ||
|
||
[cleanup] | ||
[invoke teardown] |
71 changes: 71 additions & 0 deletions
71
integration-tests/tests/replication-slot-invalidation.luxinc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
[global PS1=SH-PROMPT:] | ||
[global fail_pattern=(?i)error|fatal|no such] | ||
|
||
[global pg_container_name=] | ||
[global database_url=] | ||
|
||
[macro setup_pg initdb_args config_opts] | ||
[shell pg] | ||
-$fail_pattern | ||
|
||
!docker run --rm \ | ||
--name $pg_container_name \ | ||
-e POSTGRES_DB=electric \ | ||
-e POSTGRES_USER=postgres \ | ||
-e POSTGRES_PASSWORD=password \ | ||
-e POSTGRES_INITDB_ARGS=${initdb_args} \ | ||
-p 5432 \ | ||
postgres:14-alpine \ | ||
-c wal_level=logical ${config_opts} | ||
|
||
??database system is ready to accept connections | ||
|
||
# Reset the failure pattern to avoid false failures when Electric tries to create an already | ||
# existing publication or replication slot. | ||
- | ||
|
||
[shell get_container_port] | ||
!docker inspect $pg_container_name --format '{{json .NetworkSettings.Ports}}' | ||
?"HostIp":"0.0.0.0","HostPort":"(\d+)" | ||
[local port=$1] | ||
[global database_url=postgresql://postgres:password@localhost:$port/postgres?sslmode=disable] | ||
[endmacro] | ||
|
||
[macro seed_pg] | ||
[shell psql] | ||
!docker exec -u postgres -it $pg_container_name psql | ||
|
||
"""! | ||
CREATE TABLE items2 ( | ||
id UUID PRIMARY KEY, | ||
val1 TEXT, | ||
val2 TEXT | ||
); | ||
""" | ||
??CREATE TABLE | ||
|
||
"""! | ||
INSERT INTO | ||
items2 (id, val1, val2) | ||
SELECT | ||
gen_random_uuid(), | ||
'#' || generate_series || ' test val1 ' || repeat('012345679abcdef', 4096), | ||
'#' || generate_series || ' test val2 ' || repeat('012345679abcdef', 4096) | ||
FROM | ||
generate_series(1, 2048); | ||
""" | ||
??INSERT 0 2048 | ||
[endmacro] | ||
|
||
[macro setup_electric] | ||
[shell electric] | ||
-$fail_pattern | ||
|
||
!DATABASE_URL=$database_url ../electric_dev.sh | ||
[endmacro] | ||
|
||
[macro teardown] | ||
-$fail_pattern | ||
|
||
!docker rm -f -v $pg_container_name | ||
[endmacro] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters