@neetru/pgbouncer-arithmetic 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/sizing.d.ts +45 -0
- package/dist/sizing.js +157 -0
- package/dist/sizing.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# @neetru/coredb-pgbouncer-arithmetic
|
|
2
|
+
|
|
3
|
+
Aritmética pura de **dimensionamento do pool do PgBouncer** para as VMs
|
|
4
|
+
Postgres densas do Neetru Core DB. Função pura, determinística,
|
|
5
|
+
**zero dependências de runtime**.
|
|
6
|
+
|
|
7
|
+
## O problema — o teto de conexões (P0-4)
|
|
8
|
+
|
|
9
|
+
Uma VM Postgres densa hospeda **N bancos logicos** atrás de um único PgBouncer.
|
|
10
|
+
O `max_connections` do Postgres é um **teto rígido**: se o servidor recebe mais
|
|
11
|
+
conexões que isso, elas começam a **falhar**.
|
|
12
|
+
|
|
13
|
+
Se os tamanhos de pool do PgBouncer são cravados na mão, o problema é silencioso
|
|
14
|
+
até crescer: o 1º, 2º, 3º produto cabem; o **5º–10º produto satura o teto** e a
|
|
15
|
+
partir daí qualquer conexão nova falha — para todos os bancos da VM, não só o
|
|
16
|
+
último.
|
|
17
|
+
|
|
18
|
+
Este pacote remove o número mágico. Ele **deriva** o dimensionamento do
|
|
19
|
+
PgBouncer a partir de duas grandezas reais — `max_connections` da VM e a
|
|
20
|
+
**contagem viva de bancos** — de modo que a soma das conexões reais ao Postgres
|
|
21
|
+
nunca estoure o teto.
|
|
22
|
+
|
|
23
|
+
## API
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import {
|
|
27
|
+
computePoolSizing,
|
|
28
|
+
assertConnectionInvariant,
|
|
29
|
+
type PoolSizing,
|
|
30
|
+
} from '@neetru/coredb-pgbouncer-arithmetic';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `computePoolSizing(nBancos, maxConnections?): PoolSizing`
|
|
34
|
+
|
|
35
|
+
Dimensiona o pool do PgBouncer para uma VM.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
computePoolSizing(4); // 4 bancos, max_connections default 100
|
|
39
|
+
// { defaultPoolSize: 23, reservePoolSize: 5, maxClientConn: 500 }
|
|
40
|
+
|
|
41
|
+
computePoolSizing(10, 100); // 10 bancos
|
|
42
|
+
// { defaultPoolSize: 9, reservePoolSize: 2, maxClientConn: 500 }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Campo | Significado |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `defaultPoolSize` | `default_pool_size` — conexões de **servidor** por banco. |
|
|
48
|
+
| `reservePoolSize` | `reserve_pool_size` — folga de burst (¼ do `defaultPoolSize`). |
|
|
49
|
+
| `maxClientConn` | `max_client_conn` — conexões de **cliente** aceitas. Fixo em `500`. |
|
|
50
|
+
|
|
51
|
+
A derivação:
|
|
52
|
+
|
|
53
|
+
- `RESERVED_CONNECTIONS = 8` — superusuário + monitoring + sondas do agente,
|
|
54
|
+
tiradas do teto antes do rateio.
|
|
55
|
+
- `usable = max(maxConnections - 8, nBancos)` — conexões disponíveis para os
|
|
56
|
+
pools dos produtos; nunca menos de 1 por banco.
|
|
57
|
+
- `defaultPoolSize = max(2, floor(usable / nBancos))` — o `floor` garante a
|
|
58
|
+
**propriedade central de segurança**:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
nBancos × defaultPoolSize ≤ usable
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
ou seja, a soma das conexões reais ao Postgres nunca estoura o teto. O
|
|
65
|
+
`max(2, …)` é um **floor de viabilidade** — um pool de tamanho 1 é inútil.
|
|
66
|
+
- `reservePoolSize = max(1, floor(defaultPoolSize / 4))`.
|
|
67
|
+
- `maxClientConn = 500`.
|
|
68
|
+
|
|
69
|
+
**Sanitização (fail-safe):**
|
|
70
|
+
|
|
71
|
+
- `maxConnections` — não-finito / `< 1` / ausente → cai para `100`.
|
|
72
|
+
- `nBancos` — coagido a inteiro positivo (`floor`); NaN / `Infinity` / `≤ 0`
|
|
73
|
+
caem para `1`. O chamador **deve** passar a contagem viva real — o fallback
|
|
74
|
+
para 1 é a última linha de defesa contra lixo, não algo em que se apoiar.
|
|
75
|
+
|
|
76
|
+
**Edge de over-densidade:** quando há bancos demais numa VM pequena,
|
|
77
|
+
`floor(usable / nBancos)` pode dar 0 ou 1 e o **floor-de-2** entra. Nessa
|
|
78
|
+
região `nBancos × 2` *pode* exceder `usable` — a propriedade de segurança é
|
|
79
|
+
rompida. Isso não é um bug do cálculo: é o **sinal de uma VM genuinamente
|
|
80
|
+
over-densa**. `computePoolSizing` ainda devolve `defaultPoolSize: 2` (o mínimo
|
|
81
|
+
viável — um pool menor não funciona), mas o valor **não finge ser seguro**
|
|
82
|
+
nessa região. A correção é operacional: hospedar menos bancos ou usar uma VM
|
|
83
|
+
maior (mais `max_connections`). O chamador que opera VMs densas deve cruzar
|
|
84
|
+
`nBancos × 2 ≤ usable` e alertar. `computePoolSizing` **não lança** — é
|
|
85
|
+
aritmética pura.
|
|
86
|
+
|
|
87
|
+
### `assertConnectionInvariant({ sdkPoolMax, maxInstances, defaultPoolSize }): void`
|
|
88
|
+
|
|
89
|
+
Protege a invariante crítica de **autoscaling**:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
sdkPoolMax × maxInstances ≤ defaultPoolSize
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Cada instância do Cloud Run roda um `pg.Pool` com até `sdkPoolMax` conexões.
|
|
96
|
+
Sob autoscaling até `maxInstances` instâncias sobem ao mesmo tempo. O total que
|
|
97
|
+
o produto pode demandar do PgBouncer é `sdkPoolMax × maxInstances` — e isso não
|
|
98
|
+
pode exceder o `default_pool_size`, ou o produto satura o pool e as conexões
|
|
99
|
+
falham.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
assertConnectionInvariant({ sdkPoolMax: 2, maxInstances: 4, defaultPoolSize: 8 });
|
|
103
|
+
// ok — 2 × 4 = 8 ≤ 8
|
|
104
|
+
|
|
105
|
+
assertConnectionInvariant({ sdkPoolMax: 2, maxInstances: 5, defaultPoolSize: 8 });
|
|
106
|
+
// throws — 2 × 5 = 10 > 8
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Fail-closed:** qualquer um dos três valores que não seja inteiro positivo
|
|
110
|
+
finito **lança** — uma entrada lixo nunca passa silenciosa. Se a invariante for
|
|
111
|
+
violada, o erro nomeia os três números e diz o que fazer: reduzir `pg.Pool.max`,
|
|
112
|
+
reduzir o `maxInstances` do Cloud Run, ou aumentar o `default_pool_size`
|
|
113
|
+
hospedando menos bancos / usando uma VM maior.
|
|
114
|
+
|
|
115
|
+
## Estado
|
|
116
|
+
|
|
117
|
+
Implementado (M0 — P0-4). Suíte vitest cobrindo a derivação default, a
|
|
118
|
+
propriedade de segurança no regime normal, a região do floor-de-2, sanitização
|
|
119
|
+
de ambos os argumentos, determinismo e a invariante de autoscaling fail-closed.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @neetru/coredb-pgbouncer-arithmetic
|
|
3
|
+
*
|
|
4
|
+
* Aritmetica pura de dimensionamento do pool do PgBouncer. Uma VM Postgres
|
|
5
|
+
* densa hospeda N bancos logicos atras de um unico PgBouncer; `max_connections`
|
|
6
|
+
* e um teto rigido. Este pacote deriva o dimensionamento do PgBouncer a partir
|
|
7
|
+
* de `max_connections` e da contagem viva de bancos, e protege a invariante
|
|
8
|
+
* critica de autoscaling `sdkPoolMax * maxInstances <= defaultPoolSize`.
|
|
9
|
+
*
|
|
10
|
+
* Funcao pura, deterministica, zero dependencias de runtime. Fecha o teto de
|
|
11
|
+
* conexoes (P0-4).
|
|
12
|
+
*/
|
|
13
|
+
export { computePoolSizing, assertConnectionInvariant } from './sizing.js';
|
|
14
|
+
export type { PoolSizing } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @neetru/coredb-pgbouncer-arithmetic
|
|
3
|
+
*
|
|
4
|
+
* Aritmetica pura de dimensionamento do pool do PgBouncer. Uma VM Postgres
|
|
5
|
+
* densa hospeda N bancos logicos atras de um unico PgBouncer; `max_connections`
|
|
6
|
+
* e um teto rigido. Este pacote deriva o dimensionamento do PgBouncer a partir
|
|
7
|
+
* de `max_connections` e da contagem viva de bancos, e protege a invariante
|
|
8
|
+
* critica de autoscaling `sdkPoolMax * maxInstances <= defaultPoolSize`.
|
|
9
|
+
*
|
|
10
|
+
* Funcao pura, deterministica, zero dependencias de runtime. Fecha o teto de
|
|
11
|
+
* conexoes (P0-4).
|
|
12
|
+
*/
|
|
13
|
+
export { computePoolSizing, assertConnectionInvariant } from './sizing.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/sizing.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aritmetica de dimensionamento do pool do PgBouncer.
|
|
3
|
+
*
|
|
4
|
+
* Uma VM Postgres densa hospeda N bancos logicos atras de um unico PgBouncer.
|
|
5
|
+
* `max_connections` do Postgres e um teto rigido. Se os tamanhos de pool sao
|
|
6
|
+
* cravados na mao, o 5o-10o produto satura o teto e conexoes comecam a falhar.
|
|
7
|
+
* Este modulo deriva o dimensionamento do PgBouncer a partir de
|
|
8
|
+
* `max_connections` e da contagem viva de bancos, e protege a invariante
|
|
9
|
+
* critica de autoscaling.
|
|
10
|
+
*/
|
|
11
|
+
import type { PoolSizing } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Dimensiona o pool do PgBouncer para uma VM Postgres densa.
|
|
14
|
+
*
|
|
15
|
+
* @param nBancos Contagem viva real de bancos logicos na VM. Precisa
|
|
16
|
+
* ser um inteiro 1..10000; lixo LANCA (nao ha fallback —
|
|
17
|
+
* cair para 1 seria fail-open e poderia estourar o teto).
|
|
18
|
+
* @param maxConnections `max_connections` do Postgres da VM. Default 100 se
|
|
19
|
+
* omitido; lixo (NaN/Infinity/<1) LANCA; fracionario
|
|
20
|
+
* sofre `Math.floor`.
|
|
21
|
+
* @returns Dimensionamento puro e deterministico do pool.
|
|
22
|
+
* @throws {Error} se `nBancos` ou `maxConnections` forem invalidos.
|
|
23
|
+
*/
|
|
24
|
+
export declare function computePoolSizing(nBancos: number, maxConnections?: number): PoolSizing;
|
|
25
|
+
/**
|
|
26
|
+
* Protege a invariante critica de autoscaling:
|
|
27
|
+
*
|
|
28
|
+
* sdkPoolMax * maxInstances <= defaultPoolSize
|
|
29
|
+
*
|
|
30
|
+
* Cada instancia do Cloud Run roda um `pg.Pool` com ate `sdkPoolMax` conexoes.
|
|
31
|
+
* Sob autoscaling ate `maxInstances` instancias podem subir ao mesmo tempo. O
|
|
32
|
+
* total de conexoes que o produto pode demandar do PgBouncer e
|
|
33
|
+
* `sdkPoolMax * maxInstances`, e isso NAO pode exceder `default_pool_size`, ou
|
|
34
|
+
* o produto satura o pool e conexoes comecam a falhar.
|
|
35
|
+
*
|
|
36
|
+
* FAIL-CLOSED: qualquer um dos tres valores que nao seja inteiro positivo
|
|
37
|
+
* finito faz LANCAR — uma entrada lixo nunca passa silenciosa.
|
|
38
|
+
*
|
|
39
|
+
* @throws {Error} se algum input for invalido, ou se a invariante for violada.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assertConnectionInvariant(input: {
|
|
42
|
+
sdkPoolMax: number;
|
|
43
|
+
maxInstances: number;
|
|
44
|
+
defaultPoolSize: number;
|
|
45
|
+
}): void;
|
package/dist/sizing.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aritmetica de dimensionamento do pool do PgBouncer.
|
|
3
|
+
*
|
|
4
|
+
* Uma VM Postgres densa hospeda N bancos logicos atras de um unico PgBouncer.
|
|
5
|
+
* `max_connections` do Postgres e um teto rigido. Se os tamanhos de pool sao
|
|
6
|
+
* cravados na mao, o 5o-10o produto satura o teto e conexoes comecam a falhar.
|
|
7
|
+
* Este modulo deriva o dimensionamento do PgBouncer a partir de
|
|
8
|
+
* `max_connections` e da contagem viva de bancos, e protege a invariante
|
|
9
|
+
* critica de autoscaling.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Conexoes que NUNCA pertencem aos pools dos produtos: superusuario,
|
|
13
|
+
* monitoring, sondas (probes) do agente. Subtraidas do teto antes do rateio.
|
|
14
|
+
*/
|
|
15
|
+
const RESERVED_CONNECTIONS = 8;
|
|
16
|
+
/**
|
|
17
|
+
* Teto fixo de conexoes de CLIENTE que o PgBouncer aceita. Conexoes de cliente
|
|
18
|
+
* sao baratas (nao consomem conexao de servidor enquanto ociosas no pooling
|
|
19
|
+
* em modo transaction), por isso o valor e generoso e constante.
|
|
20
|
+
*/
|
|
21
|
+
const MAX_CLIENT_CONN = 500;
|
|
22
|
+
/** Default de `max_connections` quando o chamador nao informa um valor. */
|
|
23
|
+
const DEFAULT_MAX_CONNECTIONS = 100;
|
|
24
|
+
/**
|
|
25
|
+
* Teto sano para a contagem de bancos numa VM. Acima disso a entrada e
|
|
26
|
+
* quase certamente lixo (nenhuma VM Postgres hospeda 10 mil bancos logicos
|
|
27
|
+
* atras de um unico PgBouncer) — melhor falhar alto do que dimensionar.
|
|
28
|
+
*/
|
|
29
|
+
const MAX_N_BANCOS = 10000;
|
|
30
|
+
/**
|
|
31
|
+
* Valida e saneia `maxConnections`.
|
|
32
|
+
*
|
|
33
|
+
* - `undefined` → default 100.
|
|
34
|
+
* - Numero finito >= 1 → aceito. Fracionario sofre `Math.floor` (um
|
|
35
|
+
* `max_connections` fracionario nao faz sentido; truncar e inofensivo e
|
|
36
|
+
* leniente). Um inteiro pequeno legitimo (ex.: 20) e aceito — e um Postgres
|
|
37
|
+
* pequeno, nao lixo.
|
|
38
|
+
* - Qualquer outra coisa (NaN, Infinity, negativo, zero, nao-numero) →
|
|
39
|
+
* LANCA. Uma config de Postgres lixo nunca passa silenciosa (fail-loud).
|
|
40
|
+
*
|
|
41
|
+
* @throws {Error} se `maxConnections` for fornecido e nao for finito ou < 1.
|
|
42
|
+
*/
|
|
43
|
+
function sanitizeMaxConnections(maxConnections) {
|
|
44
|
+
if (maxConnections === undefined) {
|
|
45
|
+
return DEFAULT_MAX_CONNECTIONS;
|
|
46
|
+
}
|
|
47
|
+
if (typeof maxConnections !== 'number' || !Number.isFinite(maxConnections) || maxConnections < 1) {
|
|
48
|
+
throw new Error(`computePoolSizing: maxConnections invalido — precisa ser um numero finito >= 1 ` +
|
|
49
|
+
`(o max_connections real do Postgres), recebeu ${String(maxConnections)}.`);
|
|
50
|
+
}
|
|
51
|
+
return Math.floor(maxConnections);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Valida `nBancos`. NAO ha fallback: dimensionar um pool de conexao sem a
|
|
55
|
+
* contagem real de bancos e fail-OPEN — cair para 1 produz o MAIOR pool por
|
|
56
|
+
* banco e, se a VM hospeda muitos bancos, o total estoura o `max_connections`
|
|
57
|
+
* do Postgres. Por isso uma contagem lixo LANCA.
|
|
58
|
+
*
|
|
59
|
+
* `nBancos` precisa ser um inteiro finito no intervalo `1 <= nBancos <= 10000`.
|
|
60
|
+
*
|
|
61
|
+
* @throws {Error} se `nBancos` nao for um inteiro positivo no intervalo sano.
|
|
62
|
+
*/
|
|
63
|
+
function validateNBancos(nBancos) {
|
|
64
|
+
if (typeof nBancos !== 'number' ||
|
|
65
|
+
!Number.isInteger(nBancos) ||
|
|
66
|
+
nBancos < 1 ||
|
|
67
|
+
nBancos > MAX_N_BANCOS) {
|
|
68
|
+
throw new Error(`computePoolSizing: nBancos invalido — precisa ser um inteiro 1..${MAX_N_BANCOS} ` +
|
|
69
|
+
`(a contagem real de bancos na VM); nao da pra dimensionar um pool sem a ` +
|
|
70
|
+
`contagem real, recebeu ${String(nBancos)}.`);
|
|
71
|
+
}
|
|
72
|
+
return nBancos;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Dimensiona o pool do PgBouncer para uma VM Postgres densa.
|
|
76
|
+
*
|
|
77
|
+
* @param nBancos Contagem viva real de bancos logicos na VM. Precisa
|
|
78
|
+
* ser um inteiro 1..10000; lixo LANCA (nao ha fallback —
|
|
79
|
+
* cair para 1 seria fail-open e poderia estourar o teto).
|
|
80
|
+
* @param maxConnections `max_connections` do Postgres da VM. Default 100 se
|
|
81
|
+
* omitido; lixo (NaN/Infinity/<1) LANCA; fracionario
|
|
82
|
+
* sofre `Math.floor`.
|
|
83
|
+
* @returns Dimensionamento puro e deterministico do pool.
|
|
84
|
+
* @throws {Error} se `nBancos` ou `maxConnections` forem invalidos.
|
|
85
|
+
*/
|
|
86
|
+
export function computePoolSizing(nBancos, maxConnections) {
|
|
87
|
+
const safeMaxConn = sanitizeMaxConnections(maxConnections);
|
|
88
|
+
const safeNBancos = validateNBancos(nBancos);
|
|
89
|
+
// `usable` = conexoes disponiveis para os pools dos produtos, depois de
|
|
90
|
+
// tirar as reservadas. O `Math.max` com `safeNBancos` garante ao menos 1
|
|
91
|
+
// conexao por banco mesmo numa VM minuscula (floor(usable/nBancos) >= 1).
|
|
92
|
+
const usable = Math.max(safeMaxConn - RESERVED_CONNECTIONS, safeNBancos);
|
|
93
|
+
// `floor(usable / nBancos)` garante a propriedade central de seguranca:
|
|
94
|
+
// nBancos * defaultPoolSize <= usable
|
|
95
|
+
// ou seja, a soma das conexoes reais ao Postgres NUNCA estoura o teto.
|
|
96
|
+
//
|
|
97
|
+
// EDGE DE OVER-DENSIDADE: o `Math.max(2, ...)` impoe um floor de viabilidade
|
|
98
|
+
// — um pool com tamanho 1 e inutil. Quando ha bancos demais numa VM pequena,
|
|
99
|
+
// `floor(usable/nBancos)` pode dar 0 ou 1 e o floor-de-2 entra. Nesse caso
|
|
100
|
+
// `nBancos * 2` PODE exceder `usable` — a propriedade de seguranca e
|
|
101
|
+
// ROMPIDA. Isso NAO e silenciado por capricho: e o sinal de uma VM
|
|
102
|
+
// genuinamente over-densa. A correcao real e operacional — hospedar menos
|
|
103
|
+
// bancos ou subir para uma VM maior (mais `max_connections`). `computePoolSizing`
|
|
104
|
+
// ainda devolve `defaultPoolSize: 2` (o minimo viavel) porque um pool menor
|
|
105
|
+
// que 2 nao funciona; mas o valor NAO finge ser seguro nessa regiao. O
|
|
106
|
+
// chamador que opera VMs densas deve cruzar `nBancos * 2 <= usable` e alertar.
|
|
107
|
+
const defaultPoolSize = Math.max(2, Math.floor(usable / safeNBancos));
|
|
108
|
+
// Folga de burst — um quarto do pool base, no minimo 1.
|
|
109
|
+
const reservePoolSize = Math.max(1, Math.floor(defaultPoolSize / 4));
|
|
110
|
+
return {
|
|
111
|
+
defaultPoolSize,
|
|
112
|
+
reservePoolSize,
|
|
113
|
+
maxClientConn: MAX_CLIENT_CONN,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** Verdadeiro sse `n` e um inteiro finito estritamente positivo. */
|
|
117
|
+
function isPositiveInteger(n) {
|
|
118
|
+
return typeof n === 'number' && Number.isInteger(n) && n > 0;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Protege a invariante critica de autoscaling:
|
|
122
|
+
*
|
|
123
|
+
* sdkPoolMax * maxInstances <= defaultPoolSize
|
|
124
|
+
*
|
|
125
|
+
* Cada instancia do Cloud Run roda um `pg.Pool` com ate `sdkPoolMax` conexoes.
|
|
126
|
+
* Sob autoscaling ate `maxInstances` instancias podem subir ao mesmo tempo. O
|
|
127
|
+
* total de conexoes que o produto pode demandar do PgBouncer e
|
|
128
|
+
* `sdkPoolMax * maxInstances`, e isso NAO pode exceder `default_pool_size`, ou
|
|
129
|
+
* o produto satura o pool e conexoes comecam a falhar.
|
|
130
|
+
*
|
|
131
|
+
* FAIL-CLOSED: qualquer um dos tres valores que nao seja inteiro positivo
|
|
132
|
+
* finito faz LANCAR — uma entrada lixo nunca passa silenciosa.
|
|
133
|
+
*
|
|
134
|
+
* @throws {Error} se algum input for invalido, ou se a invariante for violada.
|
|
135
|
+
*/
|
|
136
|
+
export function assertConnectionInvariant(input) {
|
|
137
|
+
const { sdkPoolMax, maxInstances, defaultPoolSize } = input;
|
|
138
|
+
if (!isPositiveInteger(sdkPoolMax)) {
|
|
139
|
+
throw new Error(`assertConnectionInvariant: sdkPoolMax deve ser um inteiro positivo, recebeu ${String(sdkPoolMax)}.`);
|
|
140
|
+
}
|
|
141
|
+
if (!isPositiveInteger(maxInstances)) {
|
|
142
|
+
throw new Error(`assertConnectionInvariant: maxInstances deve ser um inteiro positivo, recebeu ${String(maxInstances)}.`);
|
|
143
|
+
}
|
|
144
|
+
if (!isPositiveInteger(defaultPoolSize)) {
|
|
145
|
+
throw new Error(`assertConnectionInvariant: defaultPoolSize deve ser um inteiro positivo, recebeu ${String(defaultPoolSize)}.`);
|
|
146
|
+
}
|
|
147
|
+
const demanded = sdkPoolMax * maxInstances;
|
|
148
|
+
if (demanded > defaultPoolSize) {
|
|
149
|
+
throw new Error(`Invariante de conexao violada: sdkPoolMax (${sdkPoolMax}) x maxInstances ` +
|
|
150
|
+
`(${maxInstances}) = ${demanded}, que excede defaultPoolSize (${defaultPoolSize}). ` +
|
|
151
|
+
`Sob autoscaling esse produto satura o pool do PgBouncer e conexoes vao ` +
|
|
152
|
+
`falhar. Corrija de uma destas formas: reduza pg.Pool.max (sdkPoolMax), ` +
|
|
153
|
+
`reduza o maxInstances do Cloud Run, ou aumente o default_pool_size ` +
|
|
154
|
+
`hospedando menos bancos na VM / usando uma VM maior (mais max_connections).`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=sizing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sizing.js","sourceRoot":"","sources":["../src/sizing.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos canonicos do `@neetru/coredb-pgbouncer-arithmetic`.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Dimensionamento do pool do PgBouncer derivado do `max_connections` do
|
|
6
|
+
* Postgres e da contagem viva de bancos da VM.
|
|
7
|
+
*/
|
|
8
|
+
export interface PoolSizing {
|
|
9
|
+
/**
|
|
10
|
+
* `default_pool_size` do PgBouncer — quantas conexoes de servidor o pool
|
|
11
|
+
* abre por banco.
|
|
12
|
+
*
|
|
13
|
+
* No regime normal vale a propriedade de seguranca
|
|
14
|
+
* `nBancos * defaultPoolSize <= usable` — a soma das conexoes reais ao
|
|
15
|
+
* Postgres nao estoura o teto.
|
|
16
|
+
*
|
|
17
|
+
* EXCECAO — VM over-densa: quando `floor(usable/nBancos) < 2`, entra o floor
|
|
18
|
+
* de viabilidade `defaultPoolSize: 2` (um pool menor que 2 nao funciona).
|
|
19
|
+
* Nessa regiao `nBancos * 2` PODE exceder `usable` — o `2` e um valor de
|
|
20
|
+
* viabilidade MINIMA, NAO um valor seguro. E o sinal de que a VM tem bancos
|
|
21
|
+
* demais: a correcao e operacional (hospedar menos bancos ou subir
|
|
22
|
+
* `max_connections`).
|
|
23
|
+
*/
|
|
24
|
+
defaultPoolSize: number;
|
|
25
|
+
/**
|
|
26
|
+
* `reserve_pool_size` do PgBouncer — folga de burst acima do
|
|
27
|
+
* `default_pool_size`. Derivado como um quarto do `defaultPoolSize`.
|
|
28
|
+
*/
|
|
29
|
+
reservePoolSize: number;
|
|
30
|
+
/**
|
|
31
|
+
* `max_client_conn` do PgBouncer — quantas conexoes de CLIENTE o PgBouncer
|
|
32
|
+
* aceita. E barato (conexao de cliente nao consome conexao de servidor) e
|
|
33
|
+
* fixo em 500.
|
|
34
|
+
*/
|
|
35
|
+
maxClientConn: number;
|
|
36
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@neetru/pgbouncer-arithmetic",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Dimensionamento aritmetico do pool do PgBouncer derivado do max_connections do Postgres e da contagem viva de bancos. Garante que a VM Postgres densa nunca estoure o teto de conexoes sob autoscaling. Funcao pura, zero dependencias.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "vitest run"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"typescript": "^5.6.0",
|
|
27
|
+
"vitest": "^2.1.0"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": "\u003e=20"
|
|
31
|
+
}
|
|
32
|
+
}
|