PostgreSQL యొక్క “cannot execute CREATE TABLE in a read-only transaction” ఎర్రర్ ప్రస్తుతం అనేక టీమ్ల మైగ్రేషన్లను (migrations) ఇబ్బంది పెడుతోంది, దీనివల్ల స్కీమాలు (schemas) సగం మాత్రమే అప్లై అవుతున్నాయి మరియు మైగ్రేషన్ హిస్టరీ టేబుల్స్ లాక్ అయిపోతున్నాయి. సాధారణంగా రైట్ ఆపరేషన్ (write operation) ప్రైమరీకి బదులుగా రెప్లికాకు (replica) వెళ్ళినప్పుడు ఈ ఫెయిల్యూర్ కనిపిస్తుంది, ఇది Flyway, Liquibase, Django ORM వంటి స్కీమా మార్పులపై ఆధారపడే సాధనాలను (tools) నిలిపివేస్తుంది.
ఈ ఎర్రర్ ఎందుకు వస్తుంది
ఒక ట్రాన్సాక్షన్ (transaction) read-only గా మార్క్ చేయబడినప్పుడు, PostgreSQL అన్ని రైట్స్ (writes), స్కీమా మార్పులు (schema alterations) మరియు సీక్వెన్స్ అప్డేట్లను నిలిపివేస్తుంది. మైగ్రేషన్ ఈ స్థితికి చేరుకోవడానికి అత్యంత సాధారణ కారణాలు:
- Connection poolers (ఉదాహరణకు, PgBouncer) పొరపాటున మైగ్రేషన్ కనెక్షన్ను రీడ్ రెప్లికాకు (read replica) పంపడం.
- Roles ដែល
default_transaction_read_onlyపారామీటర్ను డిఫాల్ట్గా on లో ఉంచడం. - రీడర్ మరియు రైటర్ URLలను విడివిడిగా అందించే Cloud endpoints; రీడర్ URLని ఉపయోగించడం వల్ల (AWS RDS లేదా Aurora వంటి వాటిలో ఇది సాధారణం) రైట్స్ రెప్లికాకు వెళ్తాయి.
ఈ పరిస్థితులలో ఏదైనా ఒకటి జరిగినప్పుడు, మైగ్రేషన్ ప్రక్రియ టేబుల్స్ను సృష్టించడం, కాలమ్స్ను జోడించడం లేదా సీక్వెన్స్లను అప్డేట్ చేయడం వంటివి చేస్తూ మధ్యలోనే ఆగిపోతుంది, దీనివల్ల డేటాబేస్ పాక్షికంగా మైగ్రేట్ అయిన (partially migrated) స్థితిలో ఉంటుంది.
ట్రాన్సాక్షన్ లోపల తక్షణ పరిష్కారం
మీరు ఇప్పటికే ఈ ఎర్రర్ను ఎదుర్కొంటే, మిగిలిన సెషన్ను ప్రభావితం చేయకుండా ప్రస్తుత ట్రాన్సాక్షన్ కోసం 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. మీరు ప్రైమరీ నోడ్లో ఉన్నారో లేదో సరిచూసుకోండి
ఏదైనా మైగ్రేషన్ రన్ కావడానికి ముందు ఈ క్రింది తనిఖీని జోడించండి:
SELECT CASE WHEN pg_is_in_recovery() THEN 'REPLICA' ELSE 'PRIMARY' END;
ఫలితం REPLICA అయితే, మైగ్రేషన్ను నిలిపివేయండి (abort). pg_is_in_recovery() ఫంక్షన్ స్టాండ్బై సర్వర్పై true అని రిటర్న్ చేస్తుంది, దీనివల్ల మీరు రీడ్-ఓన్లీ కాపీకి రైట్ చేయడానికి ప్రయత్నించడం లేదని నిర్ధారించుకోవచ్చు.
2. ప్రత్యేకమైన మైగ్రేషన్ రోల్స్ను (migration roles) ఉపయోగించండి
డిఫాల్ట్ ట్రాన్సాక్షన్ మోడ్ రైట్-ఎనేబుల్డ్ (write-enabled) గా ఉండేలా ఒక రోల్ను సృష్టించి, దానికి అవసరమైన అధికారాలను (privileges) మాత్రమే ఇవ్వండి:
- టార్గెట్ డేటాబేస్పై
CREATEఅనుమతి. - మైగ్రేషన్ టూల్ సెషన్ను ఓపెన్ చేయడానికి
CONNECTఅనుమతి.
సాధారణ వినియోగదారుల కోసం కొన్నిసార్లు సెట్ చేసే default_transaction_read_only = on అనే ఆట్రిబ్యూట్ను ఈ రోల్కు ఇవ్వకండి.
3. ఇన్ఫ్రాస్ట్రక్చర్ను రైటర్ ఎండ్పాయింట్కు (writer endpoint) మళ్లించండి
IaC స్క్రిప్ట్లలో (Terraform, CloudFormation, మొదలైనవి), మైగ్రేషన్ రన్నర్లు రీడర్ ఎండ్పాయింట్కు బదులుగా క్లస్టర్ యొక్క writer ఎండ్పాయింట్ను ఉపయోగించేలా కాన్ఫిగర్ చేయండి. రైటర్ ఎండ్పాయింట్ ప్రైమరీ నోడ్కు కనెక్ట్ అవుతుంది, అయితే రీడర్ ఎండ్పాయింట్ రైట్స్ను తిరస్కరించే రెప్లికాకు కనెక్ట్ అవుతుంది.
4. CI/CD గేట్ను జోడించండి
మీ పైప్లైన్లో (GitHub Actions, GitLab CI, మొదలైనవి) 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 వంటి సాధనాలు తరచుగా కనెక్షన్లను ఆటోమేటిక్గా రీట్రై చేస్తాయి. Flyway 9+ కోసం flyway.connectRetries=0 అని సెట్ చేయండి. ఇది సాధనం పదేపదే రెప్లికాను హిట్ చేయకుండా నిరోధిస్తుంది, లేకపోతే ఇది రెప్లికేషన్ లాగ్ (replication lag) పెరగడానికి మరియు వనరులను వృథా చేయడానికి దారితీస్తుంది.
తదుపరి గమనించవలసినవి
- Replication lag metrics: పెరుగుతున్న లాగ్ అనేది మైగ్రేషన్ పొరపాటున రెప్లికాను టార్గెట్ చేసిందని, దీనివల్ల రైట్ ప్రయత్నాలు క్యూ (queue) చేయబడ్డాయని సూచించవచ్చు.
- Connection-pooler routing rules: పూలర్ కాన్ఫిగరేషన్లు మైగ్రేషన్ ట్రాఫిక్ను స్పష్టంగా ప్రైమరీ హోస్ట్కు మళ్లిస్తున్నాయని నిర్ధారించుకోండి.
- Role defaults after upgrades: డేటాబేస్ అప్గ్రేడ్లు కొన్నిసార్లు రోల్ పారామీటర్లను రీసెట్ చేస్తాయి; ప్రధాన వెర్షన్ మార్పుల తర్వాత
default_transaction_read_onlyను మళ్ళీ ఆడిట్ చేయండి.
ముగింపు: read-only ట్రాన్సాక్షన్ ఎర్రర్ అనేది చాలా అరుదుగా PostgreSQL బగ్; ఇది ట్రాఫిక్ తప్పు నోడ్కు వెళ్లడం లేదా రోల్ తప్పుగా కాన్ఫిగర్ చేయబడటం వంటి సమస్యలకు సంకేతం. నోడ్ రోల్ను తనిఖీ చేయడం, ప్రత్యేకమైన మైగ్రేషన్ అకౌంట్లను ఉపయోగించడం మరియు మీ CI/CD పైప్లైన్ను బలోపేతం చేయడం ద్వారా, మీరు మైగ్రేషన్లను సజావుగా కొనసాగించవచ్చు మరియు డెవలప్మెంట్ను దెబ్బతీసే పాక్షికంగా అప్లై అయిన స్కీమాలను నివారించవచ్చు.
