Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

¿SQLite dice database is locked? Identifica al escritor y la transacción antes de subir busy_timeout

Trata SQLITE_BUSY como una línea temporal de bloqueos: confirma escritor, conexión, fase de transacción y modo de diario antes de cambiar timeout, WAL o reintentos.

Ilustración original de un escritor SQLite con el bloqueo y otra conexión esperando con un temporizador limitado.
Ilustración original: identifica al escritor y el intervalo antes de aumentar el timeout. Watch at Ease

“Database is locked” solo demuestra que SQLite no pudo obtener un bloqueo; no identifica el proceso, la conexión ni la transacción que mantiene el estado incompatible.

Construye una línea temporal por conexión, separa la contención breve de una promoción DEFERRED de lectura a escritura y verifica la reparación mínima con reintentos limitados.

Congela la evidencia del fallo

Guarda la excepción, código numérico, SQL, proceso, hilo, conexión y hora, e indica si falló en BEGIN, la primera escritura, COMMIT, un checkpoint, la recuperación o el cierre.

No borres archivos -wal o -shm ni copies solo la base principal. Enumera aplicaciones, shells, migraciones, workers y editores que puedan abrir la ruta.

Construye una línea temporal por conexión

Registra apertura, BEGIN, primera lectura, primera escritura, commit o rollback, finalización de sentencias y cierre, junto con journal_mode, timeout y modo de transacción.

Si una transacción de escritura espera red, archivos o interacción humana, mueve ese trabajo fuera antes de ajustar reintentos.

Separa la espera de una promoción fallida

SQLite admite varios lectores, pero una sola transacción de escritura. Una transacción DEFERRED que leyó primero debe promoverse; con otro escritor activo, la primera escritura puede devolver SQLITE_BUSY.

Usa BEGIN IMMEDIATE solo cuando la unidad definitivamente escribirá y tomar el turno al inicio coincide con su semántica. También puede fallar si ya existe otro escritor.

Usa busy_timeout solo para contención temporal

El timeout define cuánto esperar; no confirma otra conexión, cierra un cursor filtrado ni acorta una transacción. Mide el tiempo, los intentos y el titular del bloqueo.

Reintenta solo operaciones idempotentes o transacciones completas con efectos controlados; añade jitter y un límite estricto.

Trata WAL como modo de concurrencia, no como desbloqueo

WAL suele permitir lectores junto a un escritor, pero sigue habiendo un solo escritor. También puede aparecer SQLITE_BUSY durante bloqueo exclusivo, limpieza o recuperación.

Comprueba compatibilidad de procesos y sistema de archivos, conserva el estado WAL al respaldar y vigila checkpoints y duración de escrituras.

Aplica la reparación mínima y vuelve a probar

Cierra sentencias y conexiones, garantiza commit o rollback en cada salida, acorta transacciones y serializa escritores inevitables.

Reproduce la operación con identificadores y tiempos, confirma que no hay escrituras dobles y que agotar el presupuesto falla claramente. Para escrituras concurrentes sostenidas, evalúa una base cliente-servidor.

Ilustración conceptual original de una lectura ante la puerta de un solo escritor y ramas WAL y de espera limitada.
Concepto original: clasifica el bloqueo antes de elegir IMMEDIATE, WAL o espera limitada. Watch at Ease