PostgreSQL ਦੀ “cannot execute CREATE TABLE in a read-only transaction” ਐਰਰ ਹੁਣ ਕਈ ਟੀਮਾਂ ਲਈ ਮਾਈਗ੍ਰੇਸ਼ਨ (migrations) ਵਿੱਚ ਰੁਕਾਵਟ ਪੈਦਾ ਕਰ ਰਹੀ ਹੈ, ਜਿਸ ਨਾਲ ਸਕੀਮਾ (schemas) ਅਧੂਰੇ ਰਹਿ ਜਾਂਦੇ ਹਨ ਅਤੇ ਮਾਈਗ੍ਰੇਸ਼ਨ ਹਿਸਟਰੀ ਟੇਬਲ ਲੌਕ ਹੋ ਜਾਂਦੇ ਹਨ। ਇਹ ਫੇਲ੍ਹਰ ਆਮ ਤੌਰ 'ਤੇ ਉਦੋਂ ਆਉਂਦੀ ਹੈ ਜਦੋਂ ਕੋਈ ਰਾਈਟ ਆਪਰੇਸ਼ਨ (write operation) ਪ੍ਰਾਇਮਰੀ (primary) ਦੀ ਬਜਾਏ ਰੈਪਲੀਕਾ (replica) 'ਤੇ ਲੈਂਡ ਹੁੰਦਾ ਹੈ, ਅਤੇ ਇਹ Flyway, Liquibase, Django ORM, ਅਤੇ ਇਸ ਤਰ੍ਹਾਂ ਦੇ ਕਿਸੇ ਵੀ ਟੂਲ ਨੂੰ ਰੋਕ ਦਿੰਦਾ ਹੈ ਜੋ ਸਕੀਮਾ ਤਬਦੀਲੀਆਂ 'ਤੇ ਨਿਰਭਰ ਕਰਦੇ ਹਨ।
ਇਹ ਐਰਰ ਕਿਉਂ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ
ਜਦੋਂ ਕਿਸੇ ਟ੍ਰਾਂਜੈਕਸ਼ਨ (transaction) ਨੂੰ read-only ਵਜੋਂ ਮਾਰਕ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਤਾਂ PostgreSQL ਸਾਰੀਆਂ ਰਾਈਟਸ (writes), ਸਕੀਮਾ ਤਬਦੀਲੀਆਂ (schema alterations), ਅਤੇ ਸੀਕੁਐਂਸ ਅਪਡੇਟਸ (sequence updates) ਨੂੰ ਡਿਸੇਬਲ ਕਰ ਦਿੰਦਾ ਹੈ। ਮਾਈਗ੍ਰੇਸ਼ਨ ਦੇ ਉਸ ਸਥਿਤੀ ਵਿੱਚ ਪਹੁੰਚਣ ਦੇ ਸਭ ਤੋਂ ਆਮ ਤਰੀਕੇ ਇਹ ਹਨ:
- Connection poolers (ਜਿਵੇਂ ਕਿ PgBouncer) ਜੋ ਅਣਜਾਣੇ ਵਿੱਚ ਮਾਈਗ੍ਰੇਸ਼ਨ ਕਨੈਕਸ਼ਨ ਨੂੰ read replica 'ਤੇ ਭੇਜ ਦਿੰਦੇ ਹਨ।
- Roles ਜਿਨ੍ਹਾਂ ਵਿੱਚ
default_transaction_read_onlyਪੈਰਾਮੀਟਰ ਡਿਫੌਲਟ ਰੂਪ ਵਿੱਚ on ਸੈੱਟ ਹੁੰਦਾ ਹੈ। - Cloud endpoints ਜੋ ਵੱਖਰੇ reader ਅਤੇ writer URLs ਪ੍ਰਦਾਨ ਕਰਦੇ ਹਨ; reader URL ਦੀ ਵਰਤੋਂ ਕਰਨਾ (ਜਿਵੇਂ ਕਿ AWS RDS ਜਾਂ Aurora ਵਿੱਚ ਆਮ ਹੈ) ਰਾਈਟਸ ਨੂੰ ਰੈਪਲੀਕਾ ਵੱਲ ਰੁਟ (route) ਕਰ ਦਿੰਦਾ ਹੈ।
ਜਦੋਂ ਇਹਨਾਂ ਵਿੱਚੋਂ ਕੋਈ ਵੀ ਸਥਿਤੀ ਲਾਗੂ ਹੁੰਦੀ ਹੈ, ਤਾਂ ਮਾਈਗ੍ਰੇਸ਼ਨ ਪ੍ਰਕਿਰਿਆ ਟੇਬਲ ਬਣਾ ਸਕਦੀ ਹੈ, ਕਾਲਮ ਜੋੜ ਸਕਦੀ ਹੈ, ਜਾਂ ਸੀਕੁਐਂਸ ਅਪਡੇਟ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਅੰਤ ਵਿੱਚ ਇਹ ਰੁਕ ਜਾਂਦੀ ਹੈ, ਜਿਸ ਨਾਲ ਡੇਟਾਬੇਸ ਅਧੂਰੀ ਮਾਈਗ੍ਰੇਟ ਕੀਤੀ ਸਥਿਤੀ ਵਿੱਚ ਰਹਿ ਜਾਂਦਾ ਹੈ।
ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਦੇ ਅੰਦਰ ਤੁਰੰਤ ਹੱਲ
ਜੇਕਰ ਤੁਸੀਂ ਪਹਿਲਾਂ ਹੀ ਐਰਰ ਦਾ ਸਾਹਮਣਾ ਕਰ ਚੁੱਕੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਬਾਕੀ ਸੈਸ਼ਨ (session) ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕੀਤੇ ਬਿਨਾਂ ਮੌਜੂਦਾ ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਲਈ read-only ਫਲੈਗ ਨੂੰ ਓਵਰਰਾਈਡ (override) ਕਰ ਸਕਦੇ ਹੋ—ਇਹ ਉਦੋਂ ਬਹੁਤ ਮਹੱਤਵਪੂਰਨ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਕੋਈ ਕਨੈਕਸ਼ਨ ਪੂਲ ਦੂਜੇ ਕੰਮਾਂ ਲਈ ਉਸੇ ਸੈਸ਼ਨ ਦੀ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰਦਾ ਹੈ।
BEGIN;
SET LOCAL default_transaction_read_only = off;
SET TRANSACTION READ WRITE;
CREATE TABLE orders (id SERIAL PRIMARY KEY, total NUMERIC);
COMMIT;
SET LOCAL ਸੈਟਿੰਗ ਨੂੰ ਸਿਰਫ਼ ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਦੀ ਮਿਆਦ ਲਈ ਬਦਲਦਾ ਹੈ। ਸਧਾਰਨ SET ਦੀ ਵਰਤੋਂ ਕਰਨ ਨਾਲ ਪੂਰੇ ਸੈਸ਼ਨ ਲਈ ਤਬਦੀਲੀ ਲਾਗੂ ਹੋ ਜਾਵੇਗੀ, ਜੋ ਕਿ ਉਹਨਾਂ ਹੋਰ ਆਪਰੇਸ਼ਨਾਂ ਨੂੰ ਖਰਾਬ ਕਰ ਸਕਦੀ ਹੈ ਜਿਨ੍ਹਾਂ ਨੂੰ ਜਾਇਜ਼ ਤੌਰ 'ਤੇ read-only ਡਿਫੌਲਟ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।
ਰੋਕਥਾਮ ਦੇ ਉਪਾਅ
1. ਪੁਸ਼ਟੀ ਕਰੋ ਕਿ ਤੁਸੀਂ ਪ੍ਰਾਇਮਰੀ ਨੋਡ (primary node) 'ਤੇ ਹੋ
ਕੋਈ ਵੀ ਮਾਈਗ੍ਰੇਸ਼ਨ ਚੱਲਣ ਤੋਂ ਪਹਿਲਾਂ ਇੱਕ ਤੇਜ਼ ਚੈੱਕ ਜੋੜੋ:
SELECT CASE WHEN pg_is_in_recovery() THEN 'REPLICA' ELSE 'PRIMARY' END;
ਜੇਕਰ ਨਤੀਜਾ REPLICA ਹੈ, ਤਾਂ ਮਾਈਗ੍ਰੇਸ਼ਨ ਨੂੰ ਰੋਕ ਦਿਓ। pg_is_in_recovery() ਫੰਕਸ਼ਨ ਇੱਕ standby ਸਰਵਰ 'ਤੇ true ਰਿਟਰਨ ਕਰਦਾ ਹੈ, ਜੋ ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਤੁਸੀਂ read-only ਕਾਪੀ ਵਿੱਚ ਲਿਖਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।
2. ਸਮਰਪਿਤ (dedicated) ਮਾਈਗ੍ਰੇਸ਼ਨ ਰੋਲਸ ਦੀ ਵਰਤੋਂ ਕਰੋ
ਇੱਕ ਅਜਿਹਾ ਰੋਲ ਬਣਾਓ ਜਿਸਦਾ ਡਿਫੌਲਟ ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਮੋਡ write-enabled ਹੋਵੇ, ਅਤੇ ਇਸਨੂੰ ਸਿਰਫ਼ ਉਹੀ ਅਧਿਕਾਰ (privileges) ਦਿਓ ਜਿਨ੍ਹਾਂ ਦੀ ਇਸਨੂੰ ਲੋੜ ਹੈ:
- ਟਾਰਗੇਟ ਡੇਟਾਬੇਸ 'ਤੇ
CREATEਅਧਿਕਾਰ। - ਮਾਈਗ੍ਰੇਸ਼ਨ ਟੂਲ ਨੂੰ ਸੈਸ਼ਨ ਖੋਲ੍ਹਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ ਲਈ
CONNECTਅਧਿਕਾਰ।
ਇਸ ਰੋਲ ਨੂੰ default_transaction_read_only = on ਐਟਰੀਬਿਊਟ ਦੇਣ ਤੋਂ ਬਚੋ, ਜੋ ਕਿ ਕਦੇ-ਕਦੇ ਆਮ ਉਦੇਸ਼ਾਂ ਵਾਲੇ ਯੂਜ਼ਰਾਂ ਲਈ ਸੈੱਟ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।
3. ਇਨਫਰਾਸਟ੍ਰਕਚਰ (infrastructure) ਨੂੰ writer endpoint ਵੱਲ ਮੋੜੋ
IaC ਸਕ੍ਰਿਪਟਾਂ (Terraform, CloudFormation, ਆਦਿ) ਵਿੱਚ, ਮਾਈਗ੍ਰੇਸ਼ਨ ਰਨਰਾਂ ਨੂੰ ਕਲੱਸਟਰ ਦੇ writer endpoint ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਕੰਫਿਗਰ ਕਰੋ, ਨਾ ਕਿ reader endpoint ਦੀ। Writer endpoint ਪ੍ਰਾਇਮਰੀ ਨੋਡ ਨਾਲ ਜੁੜਿਆ ਹੁੰਦਾ ਹੈ, ਜਦੋਂ ਕਿ reader endpoint ਇੱਕ ਰੈਪਲੀਕਾ ਨਾਲ ਜੁੜਿਆ ਹੁੰਦਾ ਹੈ ਜੋ ਰਾਈਟਸ ਨੂੰ ਰੱਦ ਕਰ ਦੇਵੇਗਾ।
4. CI/CD ਗੇਟ (gate) ਜੋੜੋ
ਆਪਣੇ ਪਾਈਪਲਾਈਨ (GitHub Actions, GitLab CI, ਆਦਿ) ਵਿੱਚ ਇੱਕ ਸ਼ੈੱਲ ਸਟੈਪ (shell step) ਸ਼ਾਮਲ ਕਰੋ ਜੋ pg_is_in_recovery() ਕੁਐਰੀ ਚਲਾਵੇ। ਜੇਕਰ ਇਹ true ਰਿਟਰਨ ਕਰਦਾ ਹੈ, ਤਾਂ ਡਿਪਲਾਈਮੈਂਟ ਨੂੰ ਜਲਦੀ ਰੋਕਣ ਲਈ non-zero ਸਟੇਟਸ ਦੇ ਨਾਲ ਜੌਬ ਤੋਂ ਬਾਹਰ ਨਿਕਲ ਜਾਓ।
if psql $DATABASE_URL -c "SELECT pg_is_in_recovery()" | grep -q t; then
echo "Connected to replica – aborting migration"
exit 1
fi
5. ਮਾਈਗ੍ਰੇਸ਼ਨ-ਟੂਲ ਰੀਟ੍ਰਾਈਜ਼ (retries) ਨੂੰ ਟਿਊਨ ਕਰੋ
Flyway ਵਰਗੇ ਟੂਲ ਅਕਸਰ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਆਪਣੇ ਆਪ ਰੀਟ੍ਰਾਈ (retry) ਕਰਦੇ ਹਨ। Flyway 9+ ਲਈ flyway.connectRetries=0 ਸੈੱਟ ਕਰੋ। ਇਹ ਟੂਲ ਨੂੰ ਵਾਰ-ਵਾਰ ਰੈਪਲੀਕਾ ਨਾਲ ਜੁੜਨ ਤੋਂ ਰੋਕਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਰੈਪਲੀਕੇਸ਼ਨ ਲੈਗ (replication lag) ਵਧ ਸਕਦਾ ਹੈ ਅਤੇ ਸਰੋਤਾਂ (resources) ਦੀ ਬਰਬਾਦੀ ਹੋ ਸਕਦੀ ਹੈ।
ਅੱਗੇ ਕੀ ਦੇਖਣਾ ਹੈ
- Replication lag metrics: ਵਧਦਾ ਹੋਇਆ ਲੈਗ ਇਹ ਸੰਕੇਤ ਦੇ ਸਕਦਾ ਹੈ ਕਿ ਮਾਈਗ੍ਰੇਸ਼ਨ ਅਣਜਾਣੇ ਵਿੱਚ ਰੈਪਲੀਕਾ ਨੂੰ ਟਾਰਗੇਟ ਕਰ ਰਹੀ ਸੀ, ਜਿਸ ਨਾਲ ਰਾਈਟ ਕੋਸ਼ਿਸ਼ਾਂ ਕਤਾਰ (queue) ਵਿੱਚ ਲੱਗ ਗਈਆਂ।
- Connection-pooler routing rules: ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਪੂਲਰ ਕੰਫਿਗਰੇਸ਼ਨਾਂ ਮਾਈਗ੍ਰੇਸ਼ਨ ਟ੍ਰੈਫਿਕ ਨੂੰ ਸਪੱਸ਼ਟ ਤੌਰ 'ਤੇ ਪ੍ਰਾਇਮਰੀ ਹੋਸਟ ਵੱਲ ਰੁਟ (route) ਕਰਦੀਆਂ ਹਨ।
- Upgrades ਤੋਂ ਬਾਅਦ ਰੋਲ ਡਿਫੌਲਟਸ: ਡੇਟਾਬੇਸ ਅੱਪਗ੍ਰੇਡ ਕਦੇ-ਕਦੇ ਰੋਲ ਪੈਰਾਮੀਟਰਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰ ਦਿੰਦੇ ਹਨ; ਮੇਜਰ ਵਰਜ਼ਨ ਤਬਦੀਲੀਆਂ ਤੋਂ ਬਾਅਦ
default_transaction_read_onlyਦੀ ਮੁੜ-ਚੈਕਿੰਗ (re-audit) ਕਰੋ।
ਸਿੱਧੀ ਗੱਲ ਇਹ ਹੈ: read-only ਟ੍ਰਾਂਜੈਕਸ਼ਨ ਐਰਰ ਬਹੁਤ ਘੱਟ ਹੀ PostgreSQL ਬੱਗ ਹੁੰਦਾ ਹੈ; ਇਹ ਗਲਤ ਨੋਡ 'ਤੇ ਟ੍ਰੈਫਿਕ ਭੇਜਣ ਜਾਂ ਰੋਲ ਦੇ ਗਲਤ ਕੰਫਿਗਰੇਸ਼ਨ ਦਾ ਲੱਛਣ ਹੈ। ਨੋਡ ਰੋਲ ਦੀ
