8000 feat(lib): always use pg-pool, support pool.end() · wasabigeek/postgres-meta@116fa98 · GitHub
[go: up one dir, main page]

Skip to content

Commit 116fa98

Browse files
committed
feat(lib): always use pg-pool, support pool.end()
* Always use `Pool` from node-postgres. Originally the library allows using the `Client` class from node-postgres (by setting `pooled: false`) which is allegedly for when we only need one DB connection that we manage manually, however it turns out that using it directly is not the "happy path", and it's simpler to just use a `Pool` with max size 1 (`pool.end()` ends connections gracefully, among other things--`client.end()` ends ongoing queries abruptly). * Support `pool.end()` from the client. Since we're dynamically creating pools in the server, we want the library to be able to end unneeded pools. Note that in the typical use case of one DB connection this isn't necessary--pools are closed when the server stops.
1 parent 86863f7 commit 116fa98

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

src/lib/PostgresMeta.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ClientConfig } from 'pg'
1+
import { PoolConfig } from 'pg'
22
import PostgresMetaColumns from './PostgresMetaColumns'
33
import PostgresMetaConfig from './PostgresMetaConfig'
44
import PostgresMetaExtensions from './PostgresMetaExtensions'
@@ -15,6 +15,7 @@ import { PostgresMetaResult } from './types'
1515

1616
export default class PostgresMeta {
1717
query: (sql: string) => Promise<PostgresMetaResult<any>>
18+
end: () => Promise<void>
1819
columns: PostgresMetaColumns
1920
config: PostgresMetaConfig
2021
extensions: PostgresMetaExtensions
@@ -27,8 +28,10 @@ export default class PostgresMeta {
2728
types: PostgresMetaTypes
2829
version: PostgresMetaVersion
2930

30-
constructor(config: ClientConfig) {
31-
this.query = init(config)
31+
constructor(config: PoolConfig) {
32+
const { query, end } = init(config)
33+
this.query = query
34+
this.end = end
3235
this.columns = new PostgresMetaColumns(this.query)
3336
this.config = new PostgresMetaConfig(this.query)
3437
this.extensions = new PostgresMetaExtensions(this.query)

src/lib/db.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,44 @@
1-
import { types, Client, ClientConfig, Pool } from 'pg'
1+
import { types, Pool, PoolConfig } from 'pg'
22
import { PostgresMetaResult } from './types'
33

44
types.setTypeParser(20, parseInt)
55

6-
export const init = (
7-
config: ClientConfig,
8-
{ pooled = true } = {}
9-
): ((sql: string) => Promise<PostgresMetaResult<any>>) => {
10-
const client = pooled ? new Pool(config) : new Client(config)
11-
return async (sql: string) => {
12-
try {
13-
const { rows } = await client.query(sql)
14-
return { data: rows, error: null }
15-
} catch (e) {
16-
return { data: null, error: { message: e.message } }
17-
}
6+
export const init: (
7+
config: PoolConfig
8+
) => {
9+
query: (sql: string) => Promise<PostgresMetaResult<any>>
10+
end: () => Promise<void>
11+
} = (config) => {
12+
// XXX: Race condition could happen here: one async task may be doing
13+
// `pool.end()` which invalidates the pool and subsequently all existing
14+
// handles to `query`. Normally you might only deal with one DB so you don't
15+
// need to call `pool.end()`, but since the server needs this, we make a
16+
// compromise: if we run `query` after `pool.end()` is called (i.e. pool is
17+
// `null`), we temporarily create a pool and close is right after.
18+
let pool: Pool | null = new Pool(config)
19+
return {
20+
async query(sql) {
21+
try {
22+
if (!pool) {
23+
const pool = new Pool(config)
24+
const { rows } = await pool.query(sql)
25+
await pool.end()
26+
return { data: rows, error: null }
27+
}
28+
29+
const { rows } = await pool.query(sql)
30+
return { data: rows, error: null }
31+
} catch (e) {
32+
return { data: null, error: { message: e.message } }
33+
}
34+
},
35+
36+
async end() {
37+
const _pool = pool
38+
pool = null
39+
// Gracefully wait for active connections to be idle, then close all
40+
// connections in the pool.
41+
if (_pool) await _pool.end()
42+
},
1843
}
1944
}

0 commit comments

Comments
 (0)
0