3 days ago
Summary
We are observing a persistent PostgreSQL visibility discrepancy in our staging environment.
A Pre-Deploy process and the running web replicas connect to what we have verified is the SAME PostgreSQL cluster/database/user/schema and the SAME physical relation, but they persistently observe different committed row counts for the same query.
Impact
Our staging Staff authentication cannot complete because the running web replicas do not see a credential row that is visible and persistent from Pre-Deploy processes. External login consequently returns HTTP 401.
Reproduction
From Pre-Deploy:
SELECT COUNT(*)
FROM public.staff_credentials
WHERE staff_user_id = 1;
Result: > 0
From running web replicas, including newly opened DB connections:
same query
Result: 0
This behavior is stable and reproducible.
Strong identity checks
We verified between Pre-Deploy and web replicas:
- PostgreSQL system_identifier: 7677039476993474615
- same current_database()
- same current_user
- same current_schema()
- same pg_postmaster_start_time()
- same relation OID for public.staff_credentials: 17416
- same pg_relation_filenode: 17416
- unqualified and public-qualified relation resolve to the same OID
- exactly one staff_credentials table exists
- RLS disabled
- standard search_path
- transaction isolation: read committed
- Railway HA: disabled
- Railway PgBouncer: disabled
We also ruled out:
- SQLAlchemy identity-map/cache effects
- stale application transaction
- ORM relationship behavior (raw SQL reproduces it)
- duplicate StaffUser/Restaurant rows
- duplicate/shadow/temp relation
- different schema
- application code deleting the credential
Commit persistence
The backfill explicitly commits the transaction.
Separate later Pre-Deploy processes, which do NOT rerun the backfill, continue to observe the committed credential row. Therefore this is not only visibility inside the transaction that created it.
PostgreSQL restart test
We restarted ONLY the staging PostgreSQL service.
The restart was confirmed by pg_postmaster_start_time changing from:
2026-08-23 01:54:04 UTC
to:
2026-08-24 17:34:24 UTC
After the real restart:
- Pre-Deploy still sees the row (>0)
- web replicas still see 0
- external Staff login still returns 401
- /ready reports database.ok=true
- both web replicas remain healthy
Question
How can two processes connected to the same PostgreSQL cluster, database, user, schema, and the same relation OID/filenode persistently observe different committed row counts?
Could you please investigate the PostgreSQL service/environment internals and the connectivity path used by Pre-Deploy versus the running web replicas?
We have sanitized diagnostic instrumentation available and can perform additional read-only checks if useful. No passwords, PINs, hashes, cookies, tokens, or connection strings are included here.
3 Replies
3 days ago
This thread has been opened as a bounty so the community can help solve it.
Status changed to Open Railway • 3 days ago
3 days ago
edit: I had a reply earlier but i removed it now sorry about that
aruvine
edit: I had a reply earlier but i removed it now sorry about that
3 hours ago
Gracias, es una distinción útil. Coincidimos en que system_identifier, los OID del catálogo y los filenodes de las relaciones pueden sobrevivir a un clonado/restauración física y, por lo tanto, por sí solos no demuestran que ambos caminos de conexión estén llegando a la misma instancia viva de PostgreSQL.
Un dato adicional de nuestra evidencia es pg_postmaster_start_time(), que también coincidió entre Pre-Deploy y web, incluso después del reinicio explícito del servicio PostgreSQL. Ese valor representa estado de ejecución del servidor, no identidad de catálogo.
Para distinguir de forma más directa entre “mismo ancestro clonado” y “mismo postmaster vivo”, nuestro próximo diagnóstico será una comprobación cruzada de sesión viva: mantener abierta una conexión desde Pre-Deploy con un application_name único y, al mismo tiempo, consultar pg_stat_activity desde una réplica web en ejecución buscando exactamente ese backend activo.
Si la conexión web puede ver ese backend de Pre-Deploy, ambos caminos están llegando al mismo postmaster vivo. Si no puede verlo, eso sería una evidencia fuerte de que existen instancias PostgreSQL vivas distintas, o rutas internas diferentes, a pesar de compartir identificadores clonados.
Gracias por señalar esta posibilidad; vamos a realizar esa comprobación y compartiremos el resultado.
27 minutes ago
Seguimiento de nuestro reporte anterior: ejecutamos la prueba de estado runtime que mencionamos para descartar que la coincidencia de identificadores se debiera simplemente a dos instancias PostgreSQL clonadas.
Durante una sesión Pre-Deploy real mantuvimos abierta durante aproximadamente 120 segundos una conexión PostgreSQL con un application_name único y un advisory lock activo.
Mientras esa misma sesión continuaba viva, las dos réplicas web en ejecución consultaron independientemente pg_stat_activity.
Ambas réplicas observaron durante toda la ventana exactamente el mismo backend Pre-Deploy:
mismo pid: 5943
mismo application_name: smarttable_predeploy_live_1787889431
mismo backend_start
mismo pg_postmaster_start_time(): 2026-08-24T17:34:24.700459+00:00
mismo advisory lock activo
Se tomaron 24 muestras consecutivas, aproximadamente cada 4–5 segundos, alternando entre las dos réplicas.
En todas las muestras tomadas mientras la sesión Pre-Deploy estaba viva, ambas réplicas devolvieron probeSeen=true y detectaron el advisory lock.
Aproximadamente dos segundos después de cerrar la sesión Pre-Deploy, ambas réplicas pasaron a probeSeen=false y el advisory lock dejó de existir.
Esto confirma que Pre-Deploy y las dos réplicas web estaban conectados al mismo servidor PostgreSQL vivo en el mismo instante. Por lo tanto, la hipótesis de dos clusters PostgreSQL vivos independientes compartiendo una identidad clonada queda fuertemente descartada.
El problema original sigue sin explicación: el mismo objeto físico de PostgreSQL presentaba diferentes conteos de filas committed dependiendo de si la consulta se realizaba desde Pre-Deploy o desde las réplicas web, aun cuando ahora hemos confirmado que ambos caminos comparten el mismo estado runtime del servidor.
En este punto creemos que la causa puede estar en alguna capa de la plataforma o del entorno de ejecución a la que no tenemos visibilidad.
Podemos proporcionar la evidencia sanitizada completa —timestamps UTC, PIDs, instance IDs y resultados de las muestras— si resulta útil para continuar la investigación.