-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Handle replication slot conflicts (#1762)
Addresses #1749 - Makes publication and slot names configurable via a `REPLICATION_STREAM_ID` env variable, which can ultimately be used for multiple electric deploys - Quotes all publication and slot names to address potential issues with configurable names (alternative is to force downcase them when initialised to avoid nasty case-sensitive bugs) - Waits for a message from `Electric.LockConnection` that the lock is acquired before initialising `ConnectionManager` with the replication stream and shapes. - If more than one Electric tries to connect to the same replication slot (with the same `REPLICATION_STREAM_ID`), it will make a blocking query to acquire the lock that will resolve once the previous Electric using that slot releases it - this addresses rolling deploys, and ensures resources are initialised only once the previous Electric has released them - Could potentially switch to `pg_try_advisory_lock` that is not a blocking query but immediately returns whether the lock could be acquired and implement retries with backoff, but since using `pg_advisory_lock` simplifies the implementation I decided to start with that and see what people think. Things that I still need to address: - Currently the publication gets altered when a shape is created (adds a table and potentially a row filter) but no cleanup occurs - so the publication can potentially grow to include everything between restarts and deploys even if it is not being used. - The way I want to address this is to change the `Electric.Postgres.Configuration` to alter the publication based on _all_ active shapes rather than based on each individual one, in that case every call will update the publication as necessary and resuming/cleaning can be a matter of calling this every time a shape is deleted and once upon starting (with recovered shapes or no shapes). Can be a separate PR. - Created #1774 to address this separately --------- Co-authored-by: Oleksii Sholik <[email protected]>
- Loading branch information
Showing
20 changed files
with
633 additions
and
18 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,7 @@ | ||
--- | ||
"@core/sync-service": patch | ||
--- | ||
|
||
- Wait for advisory lock on replication slot to enable rolling deploys. | ||
- Configurable replication slot and publication name using `REPLICATION_STREAM_ID` environment variable. | ||
- Add `HealthCheckPlug` API endopint at `v1/health` that returns `waiting`, `starting`,and `active` statuses. |
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,65 @@ | ||
[doc Verify handling of an Electric crash recovery] | ||
|
||
[include macros.luxinc] | ||
|
||
[global pg_container_name=crash-recovery__pg] | ||
|
||
### | ||
|
||
## Start a new Postgres cluster | ||
[invoke setup_pg "" ""] | ||
|
||
## Add some data | ||
[invoke start_psql] | ||
[shell psql] | ||
"""! | ||
CREATE TABLE items ( | ||
id UUID PRIMARY KEY, | ||
val TEXT | ||
); | ||
""" | ||
??CREATE TABLE | ||
|
||
"""! | ||
INSERT INTO | ||
items (id, val) | ||
SELECT | ||
gen_random_uuid(), | ||
'#' || generate_series || ' test val' | ||
FROM | ||
generate_series(1, 10); | ||
""" | ||
??INSERT 0 10 | ||
|
||
## Start the sync service. | ||
[invoke setup_electric] | ||
|
||
[shell electric] | ||
??[info] Starting replication from postgres | ||
|
||
# Initialize a shape and collect the offset | ||
[shell client] | ||
# strip ANSI codes from response for easier matching | ||
!curl -v -X GET http://localhost:3000/v1/shape/items?offset=-1 | ||
?electric-shape-id: ([\d-]+) | ||
[local shape_id=$1] | ||
?electric-chunk-last-offset: ([\w\d_]+) | ||
[local last_offset=$1] | ||
|
||
## Terminate electric | ||
[shell electric] | ||
!System.halt() | ||
??$PS1 | ||
|
||
## Start the sync service again. | ||
[invoke setup_electric] | ||
[shell electric] | ||
??[info] Starting replication from postgres | ||
|
||
# Client should be able to continue same shape | ||
[shell client] | ||
!curl -v -X GET "http://localhost:3000/v1/shape/items?offset=$last_offset&shape_id=$shape_id" | ||
??HTTP/1.1 200 OK | ||
|
||
[cleanup] | ||
[invoke teardown] |
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
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,62 @@ | ||
[doc Verify handling of an Electric rolling deploy] | ||
|
||
[include macros.luxinc] | ||
|
||
[global pg_container_name=rolling-deploy__pg] | ||
|
||
### | ||
|
||
## Start a new Postgres cluster | ||
[invoke setup_pg "" ""] | ||
|
||
## Start the first sync service. | ||
[invoke setup_electric_shell "electric_1" "3000"] | ||
|
||
[shell electric_1] | ||
??[info] Acquiring lock from postgres with name electric_slot_default | ||
??[info] Lock acquired from postgres with name electric_slot_default | ||
??[info] Starting replication from postgres | ||
|
||
# First service should be health and active | ||
[shell orchestator] | ||
!curl -X GET http://localhost:3000/v1/health | ||
??{"status":"active"} | ||
|
||
## Start the second sync service. | ||
[invoke setup_electric_shell "electric_2" "3001"] | ||
|
||
## Assert that the lock is not acquired and replication does not start | ||
## in the second electric | ||
[shell electric_2] | ||
-Lock acquired from postgres|Starting replication from postgres|$fail_pattern | ||
??[info] Acquiring lock from postgres with name electric_slot_default | ||
[sleep 2] | ||
|
||
|
||
# Second service should be in waiting state, ready to take over | ||
[shell orchestator] | ||
!curl -X GET http://localhost:3000/v1/health | ||
??{"status":"active"} | ||
!curl -X GET http://localhost:3001/v1/health | ||
??{"status":"waiting"} | ||
|
||
## Terminate first electric | ||
[shell electric_1] | ||
!System.halt() | ||
|
||
# Confirm Electric process exit. | ||
??$PS1 | ||
|
||
## Lock should now be acquired and replication starting | ||
[shell electric_2] | ||
-$fail_pattern | ||
??[info] Lock acquired from postgres with name electric_slot_default | ||
??[info] Starting replication from postgres | ||
|
||
# Second service is now healthy and active | ||
[shell orchestator] | ||
!curl -X GET http://localhost:3001/v1/health | ||
??{"status":"active"} | ||
|
||
[cleanup] | ||
[invoke teardown] |
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
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
Oops, something went wrong.