Kosa la PostgreSQL la “cannot execute CREATE TABLE in a read-only transaction” sasa linakwamisha migrasheni kwa timu nyingi, likiacha miundo (schemas) ikiwa imetekelezwa nusu na majedwali ya historia ya migrasheni yakiwa yamefungwa. Kosa hili kwa kawaida hutokea wakati operesheni ya kuandika (write operation) inapoelekezwa kwenye nakala (replica) badala ya seva kuu (primary), na linazuia zana yoyote inayotegemea mabadiliko ya miundo—kama Flyway, Liquibase, Django ORM, na nyinginezo.

Kwa nini kosa hili hutokea

PostgreSQL huzima uandishi wote, mabadiliko ya miundo, na usasishaji wa mfuatano (sequence updates) wakati muamala (transaction) unapowekwa katika hali ya kusoma tu (read-only). Njia za kawaida ambazo migrasheni huishia katika hali hiyo ni:

  • Vichujio vya muunganisho (mfano, PgBouncer) ambavyo kwa bahati mbaya vinatuma muunganisho wa migrasheni kwenye nakala ya kusoma tu (read replica).
  • Nafasi za watumiaji (Roles) ambazo zina parameter ya default_transaction_read_only ikiwa imewekwa kwenye on kwa asili.
  • Njia za mawasiliano za wingu (Cloud endpoints) zinazotoa URL tofauti za kusoma na kuandika; kutumia URL ya kusoma (kama ilivyo kawaida kwa AWS RDS au Aurora) kunaelekeza maandishi kwenye nakala (replica).

Wakati mojawapo ya hali hizi inapojitokeza, mchakato wa migrasheni unaweza kutengeneza majedwali, kuongeza safu (columns), au kusasisha mfuatano lakini mwishowe ukakwama, na kuacha kanzidata katika hali ya migrasheni ya nusu.

Suluhisho la haraka ndani ya muamala

Ikiwa tayari umepata kosa hili, unaweza kupuuza alama ya kusoma tu (read-only flag) kwa muamala wa sasa bila kuathiri sehemu nyingine ya kikao (session)—jambo ambalo ni muhimu wakati kichujio cha muunganisho (connection pool) kinapotumia kikao kilekile kwa kazi nyingine.

BEGIN;
SET LOCAL default_transaction_read_only = off;
SET TRANSACTION READ WRITE;
CREATE TABLE orders (id SERIAL PRIMARY KEY, total NUMERIC);
COMMIT;

SET LOCAL inabadilisha mipangilio kwa muda tu wa muamala. Kutumia SET ya kawaida kutafanya mabadiliko hayo yadumu kwa kikao chote, jambo ambalo linaweza kuharibu operesheni nyingine ambazo zinahitaji hali ya kusoma tu kwa asili.

Hatua za kuzuia

1. Hakikisha uko kwenye node kuu (primary node)

Ongeza ukaguzi wa haraka kabla ya migrasheni yoyote kuanza:

SELECT CASE WHEN pg_is_in_recovery() THEN 'REPLICA' ELSE 'PRIMARY' END;

Ikiwa matokeo ni REPLICA, acha migrasheni. Kazi (function) ya pg_is_in_recovery() hurudisha true kwenye seva ya akiba (standby server), ikihakikisha kuwa hujaribu kuandika kwenye nakala ya kusoma tu.

2. Tumia nafasi za watumiaji (roles) maalum za migrasheni

Tengeneza nafasi (role) ambayo hali yake ya muamala kwa asili inaruhusu kuandika, na uipe ruhusa pekee inayohitajika:

  • CREATE kwenye kanzidata lengwa.
  • CONNECT ili kuruhusu zana ya migrasheni kufungua kikao.

Epuka kuipa nafasi hii sifa ya default_transaction_read_only = on ambayo wakati mwingine huwekwa kwa watumiaji wa jumla.

3. Elekeza miundombinu kwenye njia ya kuandika (writer endpoint)

Katika skripti za IaC (Terraform, CloudFormation, n.k.), sanidi zana za migrasheni (migration runners) kutumia njia ya kuandika (writer endpoint) ya kundi (cluster), si njia ya kusoma. Njia ya kuandika huunganishwa na node kuu, wakati njia ya kusoma huunganishwa na nakala (replica) ambayo itakataa maandishi.

4. Ongeza lango la CI/CD

Weka hatua ya shell kwenye mchakato wako (pipeline) (GitHub Actions, GitLab CI, n.k.) inayotekeleza swali (query) la pg_is_in_recovery(). Ikiwa itarudisha true, acha kazi hiyo kwa hali isiyo ya sifuri (non-zero status) ili kusitisha usambazaji (deployment) mapema.

if psql $DATABASE_URL -c "SELECT pg_is_in_recovery()" | grep -q t; then
  echo "Connected to replica – aborting migration"
  exit 1
fi

5. Rekebisha majaribio ya marudio ya zana za migrasheni

Zana kama Flyway mara nyingi hujaribu tena miunganisho kiotomatiki. Kwa Flyway 9+, weka flyway.connectRetries=0. Hii inazuia zana hiyo kuendelea kugonga nakala (replica), jambo ambalo linaweza kuongeza ucheleweshaji wa nakala (replication lag) na kupoteza rasilimali.

Vitu vya kuzingatia baadaye

  • Vipimo vya ucheleweshaji wa nakala (Replication lag metrics): Ucheleweshaji unaoongezeka unaweza kuashiria kuwa migrasheni ililenga nakala kwa bahati mbaya, na kusababisha majaribio ya kuandika kupangwa kwenye foleni.
  • Sheria za uelekezaji za kichujio cha muunganisho (Connection-pooler routing rules): Hakikisha mipangilio ya kichujio inaelekeza trafiki ya migrasheni moja kwa moja kwenye mwenyeji mkuu (primary host).
  • Mipangilio ya asili ya nafasi (Role defaults) baada ya maboresho: Maboresho ya kanzidata wakati mwingine hufuta mipangilio ya nafasi; kagua tena default_transaction_read_only baada ya mabadiliko makubwa ya toleo.

Hitimisho: kosa la muamala wa kusoma tu (read-only transaction) mara chache huwa si hitilafu (bug) ya PostgreSQL; ni ishara ya trafiki inayotumwa kwenye node isiyo sahihi au nafasi (role) iliyowekwa vibaya. Kwa kukagua nafasi ya node, kutumia akaunti maalum za migrasheni, na kuimarisha mchakato wako wa CI/CD, unaweza kuweka migrasheni ikiendelea vizuri na kuepuka miundo ya nusu iliyotekelezwa ambayo inazuia maendeleo ya baadaye.