or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connections.mderrors.mdindex.mdlarge-objects.mdnotifications.mdquery-processing.mdquerying.mdreplication.mdtransactions.mdtypes.md

connections.mddocs/

0

# Connection Management

1

2

Connection pooling, lifecycle management, and advanced connection options for production use.

3

4

## Capabilities

5

6

### Connection Pooling

7

8

Automatic connection pool management with configurable pool size and connection lifecycle.

9

10

```javascript { .api }

11

interface ConnectionOptions {

12

/** Maximum number of connections in the pool */

13

max?: number; // default: 10

14

15

/** Connection idle timeout in seconds */

16

idle_timeout?: number; // default: null (no timeout)

17

18

/** Connection timeout in seconds */

19

connect_timeout?: number; // default: 30

20

21

/** Maximum connection lifetime in seconds */

22

max_lifetime?: number; // default: random 30-60 minutes

23

24

/** Keep-alive interval in seconds */

25

keep_alive?: number; // default: 60

26

27

/** Backoff strategy for reconnection attempts */

28

backoff?: boolean | ((attemptNum: number) => number); // default: exponential

29

30

/** Maximum pipeline requests per connection */

31

max_pipeline?: number; // default: 100

32

33

/** Session targeting for read-write/read-only connections */

34

target_session_attrs?: 'read-write' | 'read-only' | 'primary' | 'standby' | 'prefer-standby';

35

36

/** Publications for logical replication */

37

publications?: string; // default: 'alltables'

38

39

/** Custom socket implementation */

40

socket?: any;

41

}

42

```

43

44

**Usage Examples:**

45

46

```javascript

47

// Production connection pool configuration

48

const sql = postgres({

49

host: "localhost",

50

database: "myapp",

51

max: 20, // Up to 20 concurrent connections

52

idle_timeout: 300, // Close idle connections after 5 minutes

53

connect_timeout: 10, // Timeout connection attempts after 10 seconds

54

max_lifetime: 3600, // Recycle connections every hour

55

keep_alive: 30 // Send keep-alive every 30 seconds

56

});

57

58

// Development configuration

59

const sql = postgres({

60

host: "localhost",

61

database: "myapp_dev",

62

max: 3, // Fewer connections for development

63

target_session_attrs: 'read-write' // Ensure primary connection

64

});

65

66

// High-throughput configuration

67

const sql = postgres({

68

host: "localhost",

69

database: "myapp",

70

max: 50, // More connections for high load

71

max_pipeline: 200, // Higher pipeline limit

72

max_lifetime: 1800, // Recycle connections every 30 minutes

73

keep_alive: 15 // More frequent keep-alive

74

});

75

76

// Read replica configuration

77

const sql = postgres({

78

host: ["primary.db.com", "replica.db.com"],

79

database: "myapp",

80

target_session_attrs: 'prefer-standby', // Prefer read replicas

81

max: 20,

82

idle_timeout: 60 // Shorter idle timeout

83

});

84

85

// Custom backoff strategy

86

const sql = postgres({

87

backoff: (attemptNum) => Math.min(1000 * Math.pow(2, attemptNum), 30000)

88

});

89

```

90

91

### Reserved Connections

92

93

Reserve dedicated connections for critical operations that need guaranteed database access.

94

95

```javascript { .api }

96

/**

97

* Reserve a dedicated connection from the pool

98

* @returns Promise resolving to reserved SQL instance

99

*/

100

reserve(): Promise<ReservedSql>;

101

102

interface ReservedSql extends Sql {

103

/** Release the reserved connection back to the pool */

104

release(): void;

105

}

106

```

107

108

**Usage Examples:**

109

110

```javascript

111

// Reserve connection for critical operations

112

const reservedSql = await sql.reserve();

113

114

try {

115

// This connection is guaranteed to be available

116

await reservedSql`BEGIN`;

117

118

const result = await reservedSql`

119

UPDATE critical_data SET value = ${newValue} WHERE id = ${id}

120

`;

121

122

await reservedSql`

123

INSERT INTO audit_log (action, data_id) VALUES ('update', ${id})

124

`;

125

126

await reservedSql`COMMIT`;

127

128

console.log("Critical operation completed");

129

} catch (error) {

130

await reservedSql`ROLLBACK`;

131

throw error;

132

} finally {

133

// Always release the connection

134

reservedSql.release();

135

}

136

137

// Using reserved connection for long-running operations

138

async function processLargeDataset() {

139

const reservedSql = await sql.reserve();

140

141

try {

142

for (const batch of largeDataset) {

143

await reservedSql`

144

INSERT INTO processed_data (batch_id, data)

145

VALUES (${batch.id}, ${sql.json(batch.data)})

146

`;

147

}

148

} finally {

149

reservedSql.release();

150

}

151

}

152

```

153

154

### Connection Lifecycle

155

156

Manage the lifecycle of database connections with graceful shutdown and cleanup.

157

158

```javascript { .api }

159

/**

160

* Close all connections gracefully

161

* @param options - Shutdown options

162

* @returns Promise that resolves when all connections are closed

163

*/

164

end(options?: { timeout?: number }): Promise<void>;

165

166

/**

167

* Close all connections immediately

168

* @returns Promise that resolves when all connections are closed

169

*/

170

close(): Promise<void>;

171

```

172

173

**Usage Examples:**

174

175

```javascript

176

// Graceful shutdown (recommended)

177

async function gracefulShutdown() {

178

console.log("Shutting down database connections...");

179

180

try {

181

// Wait up to 10 seconds for queries to complete

182

await sql.end({ timeout: 10 });

183

console.log("Database connections closed gracefully");

184

} catch (error) {

185

console.error("Error during graceful shutdown:", error);

186

// Force close if graceful shutdown fails

187

await sql.close();

188

}

189

}

190

191

// Handle process termination

192

process.on('SIGTERM', gracefulShutdown);

193

process.on('SIGINT', gracefulShutdown);

194

195

// Application shutdown

196

async function shutdownApp() {

197

// Stop accepting new requests first

198

server.close();

199

200

// Then close database connections

201

await sql.end({ timeout: 5 });

202

203

process.exit(0);

204

}

205

206

// Immediate shutdown (force close)

207

async function emergencyShutdown() {

208

console.log("Force closing database connections...");

209

await sql.close();

210

console.log("All connections closed immediately");

211

}

212

```

213

214

### Connection Configuration

215

216

Comprehensive connection configuration options for various deployment scenarios.

217

218

```javascript { .api }

219

interface ConnectionOptions {

220

// Basic connection

221

host?: string | string[]; // Single host or array for failover

222

port?: number | number[]; // Port(s) corresponding to host(s)

223

path?: string; // Unix socket path

224

database?: string; // Database name

225

user?: string; // Username

226

password?: string | (() => string | Promise<string>); // Password or function

227

228

// SSL configuration

229

ssl?: 'require' | 'allow' | 'prefer' | 'verify-full' | boolean | object;

230

231

// Session attributes for multi-host setups

232

target_session_attrs?: 'read-write' | 'read-only' | 'primary' | 'standby' | 'prefer-standby';

233

234

// Query configuration

235

prepare?: boolean; // Use prepared statements (default: true)

236

fetch_types?: boolean; // Auto-fetch type information (default: true)

237

238

// Event handlers

239

onnotice?: (notice: Notice) => void;

240

onparameter?: (key: string, value: any) => void;

241

onclose?: (connectionId: number) => void;

242

243

// Advanced

244

socket?: any; // Custom socket implementation

245

publications?: string; // Logical replication publications

246

}

247

```

248

249

**Usage Examples:**

250

251

```javascript

252

// Multi-host configuration with failover

253

const sql = postgres({

254

host: ["primary.db.example.com", "replica.db.example.com"],

255

port: [5432, 5432],

256

database: "myapp",

257

user: "app_user",

258

password: process.env.DB_PASSWORD,

259

target_session_attrs: "primary", // Prefer primary server

260

ssl: "require"

261

});

262

263

// Password from environment or function

264

const sql = postgres({

265

host: "localhost",

266

database: "myapp",

267

user: "app_user",

268

password: async () => {

269

// Fetch password from secret manager

270

return await getSecretValue("db_password");

271

}

272

});

273

274

// Unix socket connection

275

const sql = postgres({

276

path: "/var/run/postgresql",

277

database: "myapp",

278

user: "app_user"

279

});

280

281

// SSL configuration

282

const sql = postgres({

283

host: "secure.db.example.com",

284

database: "myapp",

285

ssl: {

286

rejectUnauthorized: true,

287

ca: fs.readFileSync('./ca-certificate.crt').toString(),

288

key: fs.readFileSync('./client-key.key').toString(),

289

cert: fs.readFileSync('./client-certificate.crt').toString()

290

}

291

});

292

293

// Event handlers

294

const sql = postgres({

295

host: "localhost",

296

database: "myapp",

297

onnotice: (notice) => {

298

console.log("PostgreSQL notice:", notice.message);

299

},

300

onparameter: (key, value) => {

301

console.log(`Server parameter changed: ${key} = ${value}`);

302

},

303

onclose: (connectionId) => {

304

console.log(`Connection ${connectionId} closed`);

305

}

306

});

307

```

308

309

### Connection State and Monitoring

310

311

Monitor connection state and pool status for debugging and metrics.

312

313

```javascript { .api }

314

interface Sql {

315

/** Access to parsed connection options */

316

readonly options: ParsedOptions;

317

318

/** Current connection parameters from server */

319

readonly parameters: ConnectionParameters;

320

}

321

322

interface ConnectionParameters {

323

application_name: string;

324

server_version: string;

325

server_encoding: string;

326

client_encoding: string;

327

is_superuser: string;

328

session_authorization: string;

329

DateStyle: string;

330

TimeZone: string;

331

[parameter: string]: string;

332

}

333

```

334

335

**Usage Examples:**

336

337

```javascript

338

// Check connection configuration

339

console.log("Database host:", sql.options.host);

340

console.log("Pool size:", sql.options.max);

341

console.log("SSL enabled:", sql.options.ssl);

342

343

// Monitor server parameters

344

console.log("Server version:", sql.parameters.server_version);

345

console.log("Timezone:", sql.parameters.TimeZone);

346

console.log("Application name:", sql.parameters.application_name);

347

348

// Custom application name

349

const sql = postgres({

350

host: "localhost",

351

database: "myapp",

352

connection: {

353

application_name: "MyApp v1.2.3"

354

}

355

});

356

357

// Monitor parameter changes

358

const sql = postgres({

359

onparameter: (key, value) => {

360

if (key === 'TimeZone') {

361

console.log(`Server timezone changed to: ${value}`);

362

}

363

}

364

});

365

```

366

367

### Connection Error Handling

368

369

Handle connection failures, timeouts, and recovery scenarios.

370

371

```javascript { .api }

372

// Connection-related error types

373

interface ConnectionError extends Error {

374

code: 'CONNECTION_DESTROYED' | 'CONNECT_TIMEOUT' | 'CONNECTION_CLOSED' | 'CONNECTION_ENDED';

375

errno: string;

376

address: string;

377

port?: number;

378

}

379

```

380

381

**Usage Examples:**

382

383

```javascript

384

// Handle connection errors

385

try {

386

const result = await sql`SELECT * FROM users`;

387

} catch (error) {

388

if (error.code === 'CONNECTION_DESTROYED') {

389

console.error("Database connection was destroyed");

390

// Implement reconnection logic

391

} else if (error.code === 'CONNECT_TIMEOUT') {

392

console.error("Database connection timed out");

393

// Implement retry logic

394

} else {

395

console.error("Database error:", error);

396

}

397

}

398

399

// Connection retry with backoff

400

async function executeWithRetry(query, maxRetries = 3) {

401

for (let attempt = 1; attempt <= maxRetries; attempt++) {

402

try {

403

return await query();

404

} catch (error) {

405

if (error.code?.includes('CONNECTION') && attempt < maxRetries) {

406

const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);

407

console.log(`Connection failed, retrying in ${delay}ms...`);

408

await new Promise(resolve => setTimeout(resolve, delay));

409

continue;

410

}

411

throw error;

412

}

413

}

414

}

415

416

// Usage

417

const result = await executeWithRetry(async () => {

418

return await sql`SELECT * FROM users WHERE active = true`;

419

});

420

```

421

422

### Connection Pool Best Practices

423

424

**Optimal Configuration:**

425

426

```javascript

427

// Production settings

428

const sql = postgres({

429

max: Math.min(20, parseInt(process.env.DB_MAX_CONNECTIONS || "10")),

430

idle_timeout: 300, // 5 minutes

431

connect_timeout: 10, // 10 seconds

432

max_lifetime: 3600, // 1 hour

433

keep_alive: 30, // 30 seconds

434

435

// Use read replicas when possible

436

target_session_attrs: process.env.DB_READ_ONLY === 'true' ? 'standby' : 'primary'

437

});

438

439

// Monitor pool exhaustion

440

let activeQueries = 0;

441

const originalQuery = sql.bind(sql);

442

443

sql = new Proxy(sql, {

444

apply: function(target, thisArg, argumentsList) {

445

activeQueries++;

446

const query = originalQuery.apply(thisArg, argumentsList);

447

448

query.finally(() => {

449

activeQueries--;

450

if (activeQueries > sql.options.max * 0.8) {

451

console.warn(`High connection usage: ${activeQueries}/${sql.options.max}`);

452

}

453

});

454

455

return query;

456

}

457

});

458

```