1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Connection-pool configuration — and an honest account of where pooling
//! does and doesn't apply.
//!
//! Pooling lives **inside** an executor, not in the [`Executor`](crate::Executor)
//! trait, because the backends differ fundamentally:
//!
//! - **`SeaOrmExecutor` (native MySQL/Postgres/SQLite)** — a
//! `sea_orm::DatabaseConnection` *is* an `sqlx` pool. Cloning the executor
//! shares that pool; `SeaOrmExecutor::connect` (in `rainier-drivers`)
//! applies a [`PoolConfig`]. This is a long-lived-process model: a background
//! task keeps idle connections warm and hands them out across concurrent
//! requests.
//!
//! - **`D1Executor` (Cloudflare D1)** — there is **no pool**. D1 is
//! request/response over a binding or the HTTP `/query` API; there is no
//! socket to keep open between calls. `PoolConfig` is meaningless here, and
//! that's not a gap to fill — it's the shape of the platform.
//!
//! ## Why serverless can't pool the usual way
//!
//! The classic pool assumes one long-running process owning a fixed set of
//! sockets. Serverless breaks both halves of that assumption:
//!
//! - **No shared process.** Each concurrent Lambda / Cloud Run / Worker
//! instance is its own isolate. A pool is per-instance, so `max_connections`
//! multiplies by the platform's concurrency: 100 warm instances × a pool of
//! 10 = 1000 sockets, which blows past a Postgres/MySQL `max_connections`
//! ceiling almost immediately. The fix is a **small** per-instance pool
//! (often exactly 1) plus a *server-side* pooler — RDS Proxy, PgBouncer, or
//! Cloudflare Hyperdrive — that does the real fan-in. [`PoolConfig::serverless`]
//! encodes the per-instance half.
//!
//! - **Frozen sockets.** Between invocations the platform may freeze the
//! instance; a pooled socket can be dead on the next thaw. `serverless()`
//! sets `test_before_acquire` so a stale connection is detected and replaced
//! rather than handed to a query that then fails.
//!
//! - **No sockets at all (Workers).** A Cloudflare Worker has no `tokio` and no
//! raw TCP, so `SeaOrmExecutor` cannot even compile to `wasm32` — it is
//! feature-gated off. Inside a Worker the only database path is
//! `D1Executor`, which pools nothing. Reaching a *Postgres* from a Worker
//! means fronting it with Hyperdrive (which pools on Cloudflare's side) and a
//! wasm-capable client — out of scope for this crate's native executor.
//!
//! So `PoolConfig` is a *server* concern. On serverless, prefer
//! [`PoolConfig::serverless`] and push real pooling to a proxy; on Workers,
//! pooling does not enter into it.
use Duration;
/// Tuning for the connection pool a native executor opens. The defaults suit a
/// long-running server; use [`PoolConfig::serverless`] for per-instance
/// serverless environments.