Hola,
No sé si soy el único, pero tengo errores de OOM regularmente cuando asigno 8Gb a Gladys. Esto provoca un reinicio de Gladys todas las noches.
Después de días de depuración, sin entender la causa, utilicé Claude para avanzar e identificar una mejor hipótesis. Y los días siguientes se identificó el problema: la manera en que se guarda la base de datos.
Contexto: guardo todos los estados de forma infinita, siempre que tenga disco.
¿Soy el único al que le pasa?
Error: el backup Gateway puede provocar un OOM-kill del proceso Node
Componentes afectados:
server/lib/gateway/gateway.backup.js
server/models/index.js (función duckDbCreateBackupInstance)
El problema: duckDbCreateBackupInstance() abre una nueva instancia DuckDB separada en el mismo archivo .duckdb que la instancia principal (ya activa en lectura/escritura):
const backupDatabase = await DuckDBInstance.create(duckDbFilePath, {
memory_limit: duckDbMemoryLimit,
access_mode: 'READ_ONLY',
});
Sin embargo, la documentación oficial del cliente Node.js « Neo » de DuckDB dice explícitamente:
« Multiple instances in the same process should not attach the same database. »
El mecanismo previsto para evitar esto es DuckDBInstanceCache.getOrCreateInstance(path), que reutiliza la misma instancia (por lo tanto, el mismo buffer pool / memory_limit) para un mismo archivo. El código actual llama a DuckDBInstance.create() directamente, lo que crea dos buffer pools independientes, cada uno limitado al mismo DUCKDB_MEMORY_LIMIT.
Resultado: el peor caso de memoria de DuckDB solo se convierte en 2 × memory_limit en lugar de 1 × memory_limit.
Agregando: la documentación de DuckDB también especifica que memory_limit « only applies to the buffer manager » — los buffers de compresión (COMPRESSION GZIP utilizado en el EXPORT DATABASE) pueden consumir además de este límite.
Prueba en producción (2 crashs idénticos, logs incluidos):
- RSS estable ~2,5 Go antes del backup (incluyendo ~1,2 Go de BASE_TABLE DuckDB)
- Paso a ~4,6 Go en menos de un minuto, justo después del log « Backing up DuckDB into a Parquet folder »
- Proceso asesinado (ExitCode=137) antes de alcanzar el log « Closing DuckDB backup instance to release memory » en el finally — por lo tanto, el crash ocurre durante la llamada EXPORT DATABASE … FORMAT PARQUET COMPRESSION GZIP, no después.
- Reproducido de manera idéntica 2 días seguidos, siempre en el momento del backup Gateway diario.
Lo que se solicita:
- Asegurarse de que duckDbCreateBackupInstance() utilice DuckDBInstanceCache.getOrCreateInstance() en lugar de DuckDBInstance.create(), para que el backup comparta el buffer pool de la instancia principal en lugar de abrir uno segundo.
- Considerar reemplazar COMPRESSION GZIP por ZSTD o SNAPPY en el EXPORT DATABASE (menos buffers de compresión, exportación más rápida).
- Eventualmente documentar que DUCKDB_MEMORY_LIMIT debe dimensionarse anticipando que dos instancias pueden coexistir durante un backup (por lo tanto, recomendar un valor ≤ 25% de la RAM asignada al contenedor, no 30-50%), siempre que el punto 1 no se corrija.
Contexto para situar el impacto: instalación con ~8 Go asignados al contenedor, BASE_TABLE de aproximadamente 1,1-1,2 Go de historial de sensores — por lo tanto, no un caso extremo, este comportamiento probablemente puede afectar a otras instalaciones con un historial considerable.







