Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

progress tracking for keep alive reply #64

Closed
wants to merge 3 commits into from

Conversation

DaemonSnake
Copy link
Contributor

context:

When receiving a keep-alive request from Postgres, replying with Posgres' current wal_end + 1
notifies the Postgres server that we fully processed up-to its wal_end+1.

issue:

As Replication.Server communicates with Replication.Publisher asynchronously this means that,
if an error occurs during the processing of a message,
we can acknowledged many more messages than we actually processed.

For a durable slot, this means that when the durable slot will restart, it will do so at the last wal_end+1
we replied with (loosing events).
The longer the transaction takes to be fully processed (many records, etc.) the higher the risk of this happening

solution proposed:

Adding a Replication.Progress Agent that stores in a :gb_sets (ordered set) the LSN of transactions.
When we start receiving the transaction it we push it
We drops it when the processing is done.
In the Replication.Server, we then only need to get the wal_end of the smallest LSN in progress as keep-alive reply.
If no transaction is in progress we can return the received wal_end+1 instead as currently.

this way we can find what wal_end are still being processed
This will be useful if some transaction have long processing time
and to improve the keep-alive reply
…ssed

Currently we always return the server's wal_end+1
This approach has a few limits, can cause some issues.

If we start processing wal_end A,
then receive a keep-alive request with wal_end=A+x and reply A+x+1,
this before A if finished processing,
then if our process crashes the server will restart at A+x+1 and
will never receive it again.

To avoid this, this PR returns wal_end+1 only if there are no processing transactions
if there are it returns the wal_end of the oldest transaction still in progress.

This way we will be guaranteed to start back from there(A and not A+x+1) if we crash.
@DaemonSnake
Copy link
Contributor Author

oh forgot that the tests uses Registry.child_spec() from the other PR

@DaemonSnake DaemonSnake marked this pull request as draft May 22, 2024 09:39
@DaemonSnake DaemonSnake deleted the keep-alive branch May 22, 2024 13:45
@cpursley
Copy link
Owner

This is a good idea, what else is needed? I just merged your other small tweak branch.

@DaemonSnake
Copy link
Contributor Author

oh sorry, I thought I had sent a comment with the closure of the PR

There a few things where I'm not enough certain of the outcome.
I think it might be wrong to send 3 times the same value.

Int64 -> The location of the last WAL byte + 1 received and written to disk in the standby.
Int64 -> The location of the last WAL byte + 1 flushed to disk in the standby.
Int64 ->The location of the last WAL byte + 1 applied in the standby.

It's not that clear but I'm afraid that replying with the current wal_end +1 for the first field will cause Postgres re-send packets.
I need to investigate further

@cpursley
Copy link
Owner

cpursley commented May 23, 2024

I see. Do you mind opening a Discussion on this topic? Maybe others have some insights.

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.

2 participants