| From: | Ajin Cherian <itsajin(at)gmail(dot)com> |
|---|---|
| To: | Andrey Borodin <x4mmm(at)yandex-team(dot)ru> |
| Cc: | pgsql-hackers mailing list <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Kirk Wolak <wolakk(at)gmail(dot)com>, nik(at)postgres(dot)ai |
| Subject: | Re: Archive-fed logical decoding: pausing recovery on slot conflict |
| Date: | 2026-09-16 05:47:16 |
| Message-ID: | CAFPTHDa9GeU3TG4bAaDVj0XrZBQpcce5N1B5ziobP4sDuav+=Q@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Sat, Sep 5, 2026 at 11:15 PM Andrey Borodin <x4mmm(at)yandex-team(dot)ru> wrote:
>
> Hi hackers,
>
> Here is v2. Self-review found that v1 advanced catalog_xmin from the
> startup process once confirmed_flush_lsn reached the pause point. That
> is not safe: confirmed output does not prove that logical decoding no
> longer needs older catalog rows.
>
Hi Andrey, Kirk, Nik,
First up, nice idea. I like it and it's simple. But one thing kept
nagging at me as I read through this, there's no ceiling on how long
recovery can stay paused.
You do mention this in the docs. Pausing doesn't guarantee the slot
survives, and if it can't, the operator has to step in and either drop
the slot or resume recovery manually. That's honest, but it does mean
the problem doesn't go away, it just moves to whoever's on call. And
the scenario I keep picturing is: the consumer just dies -
pg_recvlogical segfaulting, whatever. Recovery pauses, waiting for a
consumer that's never coming back, and as far as I can tell it just
sits there. Forever, or until someone happens to notice.
That's actually a bit worse than what happens today. Right now, a slow
consumer gets its slot killed and the standby moves on. Not great, but
at least it's self-limiting and it leaves a visible trace
(invalidation_reason, something monitoring can catch). With this
patch, a dead consumer instead quietly turns into a standby that's
stuck in the past indefinitely. If that standby feeds anything else, a
cascading replica, that stall is arguably a worse failure mode than
the one you're fixing.
Two things that I think would fix this without fighting the design
you've already got:
First, just put a limit on it. Something like a max-pause-duration
setting: if the wait drags past that, give up and let it fall back to
today's behavior (resume, let the slot get invalidated normally). That
keeps the "unattended" promise: worst case, it degrades to exactly
what happens now, rather than hanging indefinitely. And it slots in
naturally, since WaitForRecoveryToResume() already has a loop that
could just as easily check elapsed time alongside the conflict
predicate.
Second, even with a cap, it'd be nice if a long pause said something
more than once. Right now you get a single log line the moment the
pause starts, and after that the only way to know you're still stuck
is to go poll pg_get_wal_replay_pause_state() yourself and remember
when it started. A repeated warning every so often while it's stuck
would mean you find out from the logs.
I don't think either of these needs to block the core idea. The whole
appeal of the feature is that it can run unattended; a pause with no
ceiling quietly takes that back.
Regards,
Ajin Cherian
Fujitsu Australia
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Amit Kapila | 2026-09-16 05:50:47 | Re: Distinguish publication exclusions in object addresses |
| Previous Message | Hayato Kuroda (Fujitsu) | 2026-09-16 05:35:03 | RE: pg_createsubscriber does not check output_plugin_libraries |