Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SqliteError: database is locked error in Next.js + Docker #1155

Closed
deadcoder0904 opened this issue Mar 5, 2024 · 6 comments
Closed

SqliteError: database is locked error in Next.js + Docker #1155

deadcoder0904 opened this issue Mar 5, 2024 · 6 comments

Comments

@deadcoder0904
Copy link

I face this error randomly once in a while.

And idk how to debug it. I tried making a singleton.

I wanted to see if WAL mode solves it & I tried WAL mode as recommended at https://til.simonwillison.net/sqlite/enabling-wal-mode

But for some reason, I faced data loss issues which I've described in the README of the linked project below. However, I solved the data loss issues by adding Litestream as a SQLite Database Backup solution with Cloudflare R2 so whenever data is lost, Litestream recovers it with its own WAL mode. The full problem is explained well in the README. I was doing something nasty that probably won't happen in production but yeah it did have some problems.

Reproduction -> https://github.com/deadcoder0904/easypanel-nextjs-sqlite

Anyways, how can I solve this error permanently?

I've looked into it & there is one answer that you must close your database but better-sqlite3 doesn't allow to close database.

I've thought that 2 processes access the same database when in api/ route in Next.js so I tried adding export const dynamic = "force-dynamic" on every api route but that didn't work.

I tried using a default export for db instead of a named export but that didn't work.

I tried using a singleton with the help of https://github.com/epicweb-dev/remember but that didn't work either.

The problem with this error is it happens randomly once in a while. But for the last few days, it has been happening 3-4 times sometimes which is why I opened the issue now.

I'm not doing anything different. Just my big project has like 10 api routes but only 5 routes importing the db but I still get that error when the next build appears in Dockerfile on this line:

RUN pnpm build # this runs `next build` & throws an error

The error looks like:

#23 1.034 > next build
#23 1.034
#23 2.276    ▲ Next.js 14.1.1
#23 2.279    - Environments: .env.production
#23 2.279
#23 2.308    Creating an optimized production build ...
#23 40.71  ✓ Compiled successfully
#23 40.71    Linting and checking validity of types ...
#23 57.94    Collecting page data ...
#23 58.71 SqliteError: database is locked
#23 58.71     at Database.pragma (/app/node_modules/.pnpm/better-sqlite3@9.4.3/node_modules/better-sqlite3/lib/methods/pragma.js:11:44)
#23 58.71     at 57528 (/app/.next/server/app/api/admin/route.js:1:5066)
#23 58.71     at t (/app/.next/server/webpack-runtime.js:1:127)
#23 58.71     at 31062 (/app/.next/server/app/api/admin/route.js:1:4253)
#23 58.71     at t (/app/.next/server/webpack-runtime.js:1:127)
#23 58.71     at 85898 (/app/.next/server/app/api/admin/route.js:1:1156)
#23 58.71     at t (/app/.next/server/webpack-runtime.js:1:127)
#23 58.71     at r (/app/.next/server/app/api/admin/route.js:1:9460)
#23 58.71     at /app/.next/server/app/api/admin/route.js:1:9508
#23 58.71     at t.X (/app/.next/server/webpack-runtime.js:1:1191) {
#23 58.71   code: 'SQLITE_BUSY'
#23 58.71 }
#23 58.71
#23 58.71 > Build error occurred
#23 58.71 Error: Failed to collect page data for /api/admin
#23 58.71     at /app/node_modules/.pnpm/next@14.1.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.js:1258:15
#23 58.71     at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
#23 58.71   type: 'Error'
#23 58.71 }
#23 59.06  ELIFECYCLE  Command failed with exit code 1.
#23 ERROR: process "/bin/sh -c pnpm build" did not complete successfully: exit code: 1
------
 > [web builder 7/7] RUN pnpm build:
58.71   code: 'SQLITE_BUSY'
58.71 }
58.71
58.71 > Build error occurred
58.71 Error: Failed to collect page data for /api/admin
58.71     at /app/node_modules/.pnpm/next@14.1.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/build/utils.js:1258:15
58.71     at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
58.71   type: 'Error'
58.71 }
59.06  ELIFECYCLE  Command failed with exit code 1.
------
failed to solve: process "/bin/sh -c pnpm build" did not complete successfully: exit code: 1
make: *** [Makefile:3: build-development] Error 17

This happens when I try make build-production in the Terminal.

I solve it by running make build-production 3 or 4 times but I am really annoyed by this error because its happening a lot of times now.

Any ideas?

My intuition is when next build runs, all routes in api folder access the same file which open's sqlite database , i.e, ./db/index.ts & it throws this error. They all access it in milliseconds but somehow still fail.

What's the solution?

@neoxpert
Copy link
Contributor

neoxpert commented Mar 5, 2024

The error "database is locked" or "SQLITE_BUSY" is not exclusive to better-sqlite3 but sqlite3 itself.

I would guess that something within all of these uncontrollable steps and tools is doing some concurrent access to the same database file without properly closing it or finishing started transactions before the next process is trying to do its stuff.

Have you tried to limit next.js to only use 1 Process while building https://docs.uniform.dev/sitecore/deploy/how-tos/how-to-control-nextjs-threads/ ?

@mceachen
Copy link
Member

mceachen commented Mar 5, 2024

Besides just enabling WAL, you may want to adjust the busy_timeout PRAGMA.

But as @neoxpert states, this is (expected!) SQLite behavior.

@mceachen mceachen closed this as completed Mar 5, 2024
@deadcoder0904
Copy link
Author

@neoxpert thanks for the idea, i'll test it out. i didn't know that i could do it.

@mceachen yeah, i did see that somewhere online but didn't know it was a PRAGMA i can set. what's the catch though? is it ok to set? is it recommended?

@deadcoder0904
Copy link
Author

bdw, can you guys also answer why docker + sqlite wal mode gives data loss issues as stated in my readme. i'm using windows (wsl2) + docker (without docker desktop). i'm assuming its something to do with windows filesystem?

@mceachen
Copy link
Member

mceachen commented Mar 6, 2024

is it recommended?

That's up to you. I linked to the SQLite docs.

i'm using windows (wsl2) + docker

I've not had success with SQLite on WSL. It assumes a well-behaved local POSIX filesystem, which is a bit much for WSL to claim.

You may avoid WSL filesystem madness by not using WAL and disabling SHM, but at some point it's better to just run linux and route around 30 years of technical debt.

@deadcoder0904
Copy link
Author

cool.

i think this worked as i haven't faced any issues so far:

/** @type {import('next').NextConfig} */
const nextConfig = {
	experimental: {
		// recommended to solve https://github.com/WiseLibs/better-sqlite3/issues/1155
		workerThreads: false,
		cpus: 1,
	},
	.
	.
	.
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants