-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Problem
The Listener causes several problems:
- intermittent postgres core bug: LISTEN channel stops working due to postgres bug #3147
- Listener doesn't work on read replicas: Event triggers don't work on read replicas #3414 (which forces use of a primary with a hackish implementation)
- Proxies timeout the listener: Computed Relations slow at first request or after idle #3313 (reply in thread)
- gives problems on certain kubernetes deployments: Listener - connection being intermittently dropped when using Postgrest with PGCloudnative backed database. #3778
- Weird bugs with GSSAPI: prevent GSSAPI error between Listener and pool #3573 (this caused a revert for GSSAPI authorization to the database #2815)
While it's possible postgres itself improves in some of the above areas, a listen channel is still an extra long lived connection, which adds maintenance burden for the user. And I'm thinking that maybe we can do the schema cache reload in another way..
Solution
The pre_config is a function that just sets some GUCs. What if we set a schema cache version there as:
create or replace function postgrest.pre_config()
returns void as $$
select
set_config('pgrst.db_schemas', 'schema1, schema2', true)
, set_config('pgrst.scache_version', 1, true);
$$ language sql;
An event trigger then can redefine this function and increase the pgrst.scache_version
each time a db object changes.
Then during transaction variable setup, we always execute the pre_config
, which as a constant cost so it shouldn't affect performance that much:
select
-- usual set_configs...
postgrest.pre_config(..);
Then during execution of the main query, we read the scache version:
WITH pgrst_source AS (...)
SELECT
coalesce(json_agg(_postgrest_t), '[]') AS body,
nullif(current_setting('response.headers', true), '') AS response_headers,
nullif(current_setting('response.status', true), '') AS response_status,
nullif(current_setting('pgrst.scache_version', true), '') AS scache_version,
FROM ( SELECT * FROM pgrst_source ) _postgrest_t;
And cache that version, if it doesn't change we just serve the request as usual. If the version changes, we reload the schema cache.