Repository navigation
Description
Use case
We run one ArcadeDB database per customer account, thousands of them on a server, with several services sharing each database over gRPC and HTTP. At any moment only a fraction of the accounts are active, but once a database has been opened it stays open, with its buckets' and indexes' files and its memory, until someone runs close database. So the server's open files and heap grow with every customer that has ever connected since startup, not with the ones active now.
On a small test server we ran out of heap at about 500 open databases. Each of our databases holds about 190 open files: 3,003 files for 16 databases.
Current behavior (26.10.2)
- I found no setting among the server settings that closes idle databases.
POST /api/v1/server {"command":"close database <name>"}works, and frees that database's files straight away (in our case 3,003 → 2,812).- gRPC: the next query on a closed database reopens it transparently (about 50 ms).
- HTTP: the next query on a closed database fails with
404 DatabaseNotAvailableExceptionuntil someone runsopen database <name>. - A transaction open when the database is closed fails with
DatabaseIsClosedException, and its rollback then fails withAborted.
Because the decision needs every client's activity, it can't be made well by any single client. Today we would need a custom server plugin that samples ServerDatabase.getStats() counters and calls ServerControlPlane.closeDatabase().
Proposal
A native, opt-in idle close, configured like other server settings, for example:
| Setting | Meaning | Suggested default |
|---|---|---|
arcadedb.server.databaseIdleTimeout |
Close a database no client has used for this long (0 = never) | 0 (off) |
arcadedb.server.databaseIdleCheckInterval |
How often to look for idle databases | 60s |
arcadedb.server.databaseIdleMaxClosesPerCheck |
Bound closes per check, to avoid bursts | 10 |
arcadedb.server.databaseIdleExclude |
Databases never closed | empty |
The behavior we'd hope for:
- "Idle" means no activity from any protocol: no queries, commands, open transactions or sessions. A database with an open transaction is never closed, even if that transaction has been quiet.
- Reopen on demand over every protocol: HTTP, Bolt and PostgreSQL wire, as gRPC already does, instead of
DatabaseNotAvailableException. - Optionally, a cap on open databases (
arcadedb.server.maxOpenDatabases) that closes the least recently used ones when exceeded, which is useful for sizing memory. - Metrics: databases closed for idleness, and reopens.
Why native
The server is the only place that sees every client's use, so it can judge idleness exactly and never close a database mid-transaction. Client-side or plugin approaches have to approximate both. It would make the "one database per tenant" pattern, which ArcadeDB's multi-database design suits well, practical at thousands of tenants per server.
Environment
ArcadeDB 26.10.2, default profile, gRPC plugin enabled, many databases per server.
Activity
fix(#11068): narrow the cross-thread transaction probe's catch, compa…
test(#11068): idle-close tests retry the check, so background activit…
perf(#11068): the idle check reads the HTTP and WebSocket sessions on…
fix(#11068): idle checks take turns under their own lock, failed idle…
perf(#11068): the cap orders its candidates with one primitive key each
fix(#11068, #11067, #11059): a close for reopen refuses new transacti…
feat(#11068, #11067, #11061, #11059, #11054): idle databases close an…
lvca commentedon Nov 2, 2026
Fixed in #11118, available from 26.11.1.
The server can now close databases nobody uses and reopen them on the next request, over every protocol (HTTP, gRPC, PostgreSQL, Bolt, Gremlin, MCP). It is off by default:
arcadedb.server.databaseIdleTimeout(ms,0= disabled): close a database after this long without activity.arcadedb.server.databaseIdleCheckInterval(default 60000 ms) andarcadedb.server.databaseIdleMaxClosesPerCheck(default 10).arcadedb.server.databaseIdleExclude: comma-separated databases never closed.arcadedb.server.maxOpenDatabases(0= unlimited): above this, the least recently used idle databases are closed.A database is never closed while it has an open transaction (including an HTTP session), a running query or async work, and replicated (HA) databases are skipped. Closed databases still appear in the database list and can be dropped. New metrics:
arcadedb.server.databases.idle_closed,.reopenedand.idle_close_failed.Note: a database closed for idleness is not included in scheduled backups until it reopens.
❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.
feat(#11068, #11067, #11061, #11059, #11054): idle databases close an…