Database pool versus process scope
The short version
A database connection pool is a reusable set of database connections for one particular database configuration. A process is one running Neos program, such as one backend server or one task runner.
The database provider determines what Neos can observe:
| Scope | Meaning | Neos providers |
|---|---|---|
pool |
The provider reports each connection pool separately. Neos can inspect each pool, then adds them together before exporting metrics. | PostgreSQL through Npgsql |
process |
The provider reports only one total for the whole running program. Neos cannot see the individual pools inside that total. | SQL Server through SqlClient |
pool does not mean that Prometheus receives one series per pool. Neos deliberately exports only one provider-wide aggregate, because pool identity would effectively reveal the tenant database and make metric cardinality grow with the number of tenants.
Picture a multitenant backend
Suppose a single Neos backend process serves two tenants. Each tenant uses a different database, so each has its own connection pool.
One running Neos backend process
|
|-- Tenant A database pool
| |-- 3 connections currently active
| |-- 1 connection currently idle
| `-- maximum: 10 connections
|
`-- Tenant B database pool
|-- 2 connections currently active
|-- 4 connections currently idle
`-- maximum: 10 connections
There are two pools, but they belong to one process.
PostgreSQL / Npgsql: individual-pool observations
Npgsql reports the values for both pools separately to Neos. Neos can therefore do this internally:
Observed by Neos internally
Tenant A pool: active 3, idle 1, maximum 10
Tenant B pool: active 2, idle 4, maximum 10
-----------------------------------------------
Aggregate: active 5, idle 5, maximum 20
Neos then exports the aggregate, not the two tenant-specific rows:
neos_db_pool_connections{
neos_db_provider="PostgreSQL",
connection_state="active"
} 5
neos_db_pool_connections{
neos_db_provider="PostgreSQL",
connection_state="idle"
} 5
neos_db_pool_max_connections{
neos_db_provider="PostgreSQL"
} 20
Npgsql gives Neos a per-pool view before aggregation. Neos does not identify either pool in Prometheus.
From these values, Prometheus can calculate the combined active-pool saturation as \(5 / 20 = 25\%\).
SQL Server / SqlClient: process-wide observations
SqlClient only reports counters for the entire running program. Even if the backend process contains two tenant pools, the provider gives Neos only this kind of information:
One running Neos backend process
|
`-- SqlClient reports: active 5, idle 5
It does not say:
- which tenant pool has the 5 active connections;
- whether the split is 3 + 2, 5 + 0, or something else;
- the configured maximum for either pool; or
- a total maximum across all pools.
So Neos exports only the counters it can know:
neos_db_pool_connections{
neos_db_provider="SQLServer",
connection_state="active"
} 5
neos_db_pool_connections{
neos_db_provider="SQLServer",
connection_state="idle"
} 5
There is no neos_db_pool_max_connections series for SQL Server. Its absence means "SqlClient cannot report this value"; it does not mean the maximum is zero or unlimited.
What an operator can conclude
| Question | PostgreSQL (pool) |
SQL Server (process) |
|---|---|---|
| How many active connections does this provider use in this process? | Yes, as the sum of all pools | Yes, as one process-wide count |
| How many idle connections does this provider hold in this process? | Yes, as the sum of all pools | Yes, as one process-wide count |
| What is the combined configured maximum? | Yes, as the sum of pool maxima | No |
| Which tenant database is consuming connections? | No; Neos deliberately does not export this | No; the provider does not report it |
| Can the standard utilization ratio be calculated? | Yes: active divided by maximum | No: maximum is unavailable |
A useful mental model
Think of a process as an office building and pools as separate rooms inside it.
- With PostgreSQL, Npgsql lets Neos look into every room, count the occupied and empty chairs, and add the room capacities. Neos reports only the building total so it does not publish a tenant-by-tenant floor plan.
- With SQL Server, SqlClient stands outside the building and says only, "There are 5 people working and 5 seats empty somewhere in the building." It does not identify rooms or state how many chairs the building can hold.
The provider determines how Neos obtains the number, not how many Prometheus series are emitted.
Separate processes remain separate
The backend server and task runner are different processes, each with its own connection pools and /metrics endpoint. A background server method runs in the task runner, so its database connections appear in the task-runner metrics, not in the backend-server metrics.
When multiple backend replicas exist, each replica also reports independently. Prometheus can sum or compare their values, but it must not treat a metric from one process as the total for the whole deployment unless the query aggregates across the relevant processes.