postgres read‐only - ghdrako/doc_snipets GitHub Wiki
SET default_transaction_read_only TO off; -- current session
ALTER USER [username] SET default_transaction_only TO off; -- user level
ALTER DATABASE [dbname] SET default_transaction_only TO off; -- database level
ALTER SYSTEM SET default_transaction_read_only TO off; -- system level This will add or update the setting in data/postgresql/postgresql.auto.conf
SELECT * from pg_settings WHERE name = 'default_transaction_read_only';
PostgreSQL has a configuration parameter call default_transaction_read_only. Setting default_transaction_read_only globally to on forces all connections to disallow writes to the database. default_transaction_read_only is a reloadable parameter, so you do not need to restart your Postgres instance to use it.
ALTER SYSTEM SET default_transaction_read_only TO on;
SELECT pg_reload_conf();
SHOW default_transaction_read_only;
postgres=# INSERT INTO abc VALUES (2) RETURNING id;
ERROR: cannot execute INSERT in a read-only transaction
- default_transaction_read_only can be overriden in a session, even if the value is set database-wide
postgres=# SHOW default_transaction_read_only ;
default_transaction_read_only
-------------------------------
on
(1 row)
postgres=# SET default_transaction_read_only TO off;
SET
postgres=# INSERT INTO abc VALUES (2) RETURNING id;
id
----
2
(1 row)
INSERT 0 1
- when utilizing
default_transaction_read_onlywith an application, you must also ensure your app can be configured to send only read queries to the database, ensuring a smooth user experience.
The Strategy
- Disable connections to the database (not the cluster).
alter database <dbname> with allow_connections = off;
- Set the database's default_transaction_read_only setting to true.
alter database <dbname> set default_transaction_read_only = true; --ALTER DATABASE name_of_database SET default_transaction_read_only to ON;
- Terminate the existing connections to that database.
DO $X$ BEGIN
-- kill open idle connections, try up to 9x. Last time, kill regardless
FOR i IN 1..10 LOOP
PERFORM pg_terminate_backend(pid) from pg_stat_activity where usename = 'gitlab'
and (i >= 10 OR state in ('idle', 'disabled' ));
PERFORM pg_stat_clear_snapshot();
EXIT WHEN NOT EXISTS ( select pid from pg_stat_activity where usename = 'gitlab' );
RAISE NOTICE 'pg backends still open: sleeping 2 seconds';
PERFORM pg_sleep(2);
PERFORM pg_stat_clear_snapshot();
END LOOP;
-- send notice if still open connections
IF EXISTS ( select pid from pg_stat_activity where usename = 'gitlab' ) THEN
RAISE NOTICE 'Hung backends. Backup might not be 100%% consistent';
END IF;
END;$X$;
- Re-enable (read-only) connections.
alter database gitlabhq with allow_connections = on;