# Operations and capacity planning

Understand AskTable's default database connection capacity and troubleshoot DATABASE\_BUSY.

部署说明 · 模块: deploy · 管理人员 · 部署形态：资料未说明 · 已确认产品版本：资料未说明 · 来源：现有文档

**Check**

The default configuration suits typical single-server deployments. If `DATABASE_BUSY` is not recurring and you have not added Web or Worker processes, there is no need to change the connection pools.

## Default connection capacity

| Item                                              |                          Default |
| ------------------------------------------------- | -------------------------------: |
| Web processes                                     |                              `1` |
| Main database connection limit per Web process    | `20` (pool `10` + overflow `10`) |
| Worker processes                                  |                              `1` |
| Main database connection limit per Worker process |   `10` (pool `5` + overflow `5`) |
| Workbook connection limit per process             |                             `10` |
| Built-in PostgreSQL `max_connections`             |                            `100` |

With Workbook enabled by default, the application's conservative peak is `51` connections:

```text
Web 20 + Worker 10 + Workbook 20 + LISTEN/NOTIFY 1 = 51
```

Under the default process configuration above, PostgreSQL's limit of `100` leaves headroom. Recalculate when adding processes or sharing the instance with other applications. `POOL_SIZE` is the number of connections retained by the pool, not its connection limit; add `MAX_OVERFLOW` to obtain the limit.

## When DATABASE\_BUSY occurs

`DATABASE_BUSY` means AskTable temporarily could not obtain a database connection, or PostgreSQL has reached its connection limit. The page retries automatically; you can retry manually if it has not recovered.

If the error recurs:

1. Check logs to determine whether it comes from Web requests or background refreshes.
2. When background refreshes are busy, lower `AT_WORKER_MAX_JOBS` first.
3. If PostgreSQL reports exhausted connections, do not keep increasing the connection pool.
4. Increase the corresponding Web or Worker pool only after confirming that PostgreSQL still has headroom and the local pool is timing out while waiting.

## When adding processes

Each additional Web process adds one Web main database pool, at most one Workbook pool, and one `LISTEN/NOTIFY` connection. Each additional Worker process adds one Worker main database pool and at most one Workbook pool.

The recommended adjustment order is: shorten transactions, lower background concurrency, adjust the corresponding role's connection pool, and only then increase the PostgreSQL limit. Always reserve at least 10 connections for migrations and manual troubleshooting.

**Complete configuration reference**

All settings are static environment variables; restart the corresponding processes after making changes.

| Setting                     |                                                 Default | Description                                                                   |
| --------------------------- | ------------------------------------------------------: | ----------------------------------------------------------------------------- |
| `AT_SERVER_WORKERS`         |                                                     `1` | Number of Web processes; the command-line `--workers` option takes precedence |
| `AT_WEB_DB_POOL_SIZE`       |                                                    `10` | Main database connections retained per Web process                            |
| `AT_WEB_DB_MAX_OVERFLOW`    |                                                    `10` | Additional temporary connections when the Web pool is full                    |
| `AT_WORKER_NUM_PROCS`       |                                                     `1` | Number of Worker processes                                                    |
| `AT_WORKER_MAX_JOBS`        |                                                    `10` | Maximum concurrent jobs per Worker                                            |
| `AT_WORKER_DB_POOL_SIZE`    |                                                     `5` | Main database connections retained per Worker process                         |
| `AT_WORKER_DB_MAX_OVERFLOW` |                                                     `5` | Additional temporary connections when the Worker pool is full                 |
| `AT_DB_POOL_TIMEOUT`        |                                                    `30` | Maximum seconds to wait for a main database connection                        |
| `AT_DB_POOL_RECYCLE`        |                                                   `300` | Main database connection recycling interval in seconds                        |
| `WORKBOOK_PG_DSN`           | A separate database in the local main database instance | A non-empty value enables it; explicitly set an empty value to disable it     |
| `AT_WORKBOOK_POOL_MIN`      |                                                     `1` | Minimum Workbook connections retained per process                             |
| `AT_WORKBOOK_POOL_MAX`      |                                                    `10` | Maximum Workbook connections used per process                                 |

Web and Worker pool capacities are configured separately; both process types share timeout and recycling intervals. All pool parameters must be non-negative, and Workbook requires `0 <= MIN <= MAX`.

**Calculate the exact connection limit**

`B` is `AT_WORKBOOK_POOL_MAX` when Workbook is enabled, or `0` otherwise.

```text
Application connection limit =
  AT_SERVER_WORKERS
    × (AT_WEB_DB_POOL_SIZE + AT_WEB_DB_MAX_OVERFLOW + B + 1)
  + AT_WORKER_NUM_PROCS
    × (AT_WORKER_DB_POOL_SIZE + AT_WORKER_DB_MAX_OVERFLOW + B)
```

The application connection limit plus at least 10 operations connections must be less than PostgreSQL's available connections for ordinary users. That number is `max_connections` minus `reserved_connections` and `superuser_reserved_connections`.

**Inspect connection usage**

Check PostgreSQL limits:

```sql
SHOW max_connections;
SHOW reserved_connections;
SHOW superuser_reserved_connections;
```

Check connection sources and long transactions:

```sql
SELECT application_name, state, count(*) AS connections,
       max(now() - xact_start) AS longest_transaction
FROM pg_stat_activity
WHERE datname IN ('asktable', 'asktable_workbook')
GROUP BY application_name, state
ORDER BY connections DESC;
```

Check container logs:

```bash
docker compose logs --since=30m asktable | grep -E 'DATABASE_BUSY|creating postgresql pool|refresh_table_task'
docker compose logs --since=30m asktable-pg
```

**Note**

When using external PostgreSQL, use the actual connection limit provided by the database provider. AskTable does not change it automatically.

See [Private deployment (Docker)](https://docs.asktable.com/en/deploy/docker) and [Version upgrades and migration](https://docs.asktable.com/en/deploy/migration) for deployment and upgrade procedures.
