Skip to content

Commit 2e01c2b

Browse files
committed
Add connect_timeout with a default of 30 seconds
1 parent 162b4b3 commit 2e01c2b

File tree

4 files changed

+77
-28
lines changed

4 files changed

+77
-28
lines changed

README.md

+21-15
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,26 @@ You can use either a `postgres://` url connection string or the options to defin
4444

4545
```js
4646
const sql = postgres('postgres://username:password@host:port/database', {
47-
host : '', // Postgres ip address or domain name
48-
port : 5432, // Postgres server port
49-
path : '', // unix socket path (usually '/tmp')
50-
database : '', // Name of database to connect to
51-
username : '', // Username of database user
52-
password : '', // Password of database user
53-
ssl : false, // True, or options for tls.connect
54-
max : 10, // Max number of connections
55-
idle_timeout: 0, // Idle connection timeout in seconds
56-
types : [], // Array of custom types, see more below
57-
onnotice : fn // Defaults to console.log
58-
onparameter : fn // (key, value) when server param change
59-
debug : fn // Is called with (connection, query, parameters)
60-
transform : {
47+
host : '', // Postgres ip address or domain name
48+
port : 5432, // Postgres server port
49+
path : '', // unix socket path (usually '/tmp')
50+
database : '', // Name of database to connect to
51+
username : '', // Username of database user
52+
password : '', // Password of database user
53+
ssl : false, // True, or options for tls.connect
54+
max : 10, // Max number of connections
55+
idle_timeout : 0, // Idle connection timeout in seconds
56+
connect_timeout : 30, // Connect timeout in seconds
57+
types : [], // Array of custom types, see more below
58+
onnotice : fn // Defaults to console.log
59+
onparameter : fn // (key, value) when server param change
60+
debug : fn // Is called with (connection, query, params)
61+
transform : {
6162
column : fn, // Transforms incoming column names
6263
value : fn, // Transforms incoming row values
6364
row : fn // Transforms entire rows
6465
},
65-
connection : {
66+
connection : {
6667
application_name : 'postgres.js', // Default application_name
6768
... // Other connection parameters
6869
}
@@ -578,6 +579,11 @@ This error is thrown if the user has called [`sql.end()`](#sql_end) and performe
578579
579580
This error is thrown for any queries that were pending when the timeout to [`sql.end({ timeout: X })`](#sql_destroy) was reached.
580581

582+
##### CONNECTION_CONNECT_TIMEOUT
583+
> write CONNECTION_CONNECT_TIMEOUT host:port
584+
585+
This error is thrown if the startup phase of the connection (tcp, protocol negotiation and auth) took more than the default 30 seconds or what was specified using `connect_timeout` or `PGCONNECT_TIMEOUT`.
586+
581587
## Migration tools
582588

583589
Postgres.js doesn't come with any migration solution since it's way out of scope, but here are some modules that supports Postgres.js for migrations:

lib/connection.js

+15-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ function Connection(options = {}) {
1414
onparameter,
1515
transform,
1616
idle_timeout,
17+
connect_timeout,
1718
onnotify,
1819
onnotice,
1920
parsers
@@ -27,6 +28,7 @@ function Connection(options = {}) {
2728
let open = false
2829
let ready = false
2930
let statements = {}
31+
let connect_timer
3032

3133
const queries = Queue()
3234
, id = count++
@@ -128,7 +130,17 @@ function Connection(options = {}) {
128130

129131
open
130132
? socket.write(buffer)
131-
: (messages.push(buffer), socket.connect())
133+
: (messages.push(buffer), connect())
134+
}
135+
136+
function connect() {
137+
connect_timeout && (connect_timer = setTimeout(connectTimedOut, connect_timeout * 1000))
138+
socket.connect()
139+
}
140+
141+
function connectTimedOut() {
142+
error(errors.connection('CONNECT_TIMEOUT', options))
143+
socket.destroy()
132144
}
133145

134146
function simple(str, query) {
@@ -161,6 +173,7 @@ function Connection(options = {}) {
161173
}
162174

163175
function onready(err) {
176+
connect_timer && (clearTimeout(connect_timer), connect_timer = null)
164177
if (err) {
165178
if (backend.query) {
166179
err.stack += backend.query.origin.replace(/.*\n/, '\n')
@@ -210,6 +223,7 @@ function Connection(options = {}) {
210223
}
211224

212225
function close() {
226+
connect_timer && (clearTimeout(connect_timer), connect_timer = null)
213227
error(errors.connection('CLOSED', options))
214228
statements = {}
215229
messages = []

lib/index.js

+13-12
Original file line numberDiff line numberDiff line change
@@ -490,19 +490,20 @@ function parseOptions(a, b) {
490490
return Object.assign({
491491
host,
492492
port,
493-
path : o.path || host.indexOf('/') > -1 && host + '/.s.PGSQL.' + port,
494-
database : o.database || o.db || (url.pathname || '').slice(1) || env.PGDATABASE || 'postgres',
495-
user : o.user || o.username || auth[0] || env.PGUSERNAME || env.PGUSER || osUsername(),
496-
pass : o.pass || o.password || auth[1] || env.PGPASSWORD || '',
497-
max : o.max || url.query.max || 10,
498-
types : o.types || {},
499-
ssl : o.ssl || url.ssl || false,
500-
idle_timeout: o.idle_timeout || warn(o.timeout, 'The timeout option is deprecated, use idle_timeout instead'),
501-
onnotice : o.onnotice,
502-
onparameter : o.onparameter,
503-
transform : Object.assign({}, o.transform),
493+
path : o.path || host.indexOf('/') > -1 && host + '/.s.PGSQL.' + port,
494+
database : o.database || o.db || (url.pathname || '').slice(1) || env.PGDATABASE || 'postgres',
495+
user : o.user || o.username || auth[0] || env.PGUSERNAME || env.PGUSER || osUsername(),
496+
pass : o.pass || o.password || auth[1] || env.PGPASSWORD || '',
497+
max : o.max || url.query.max || 10,
498+
types : o.types || {},
499+
ssl : o.ssl || url.ssl || false,
500+
idle_timeout : o.idle_timeout || url.query.idle_timeout || env.PGIDLE_TIMEOUT || warn(o.timeout, 'The timeout option is deprecated, use idle_timeout instead'),
501+
connect_timeout : o.connect_timeout || url.query.connect_timeout || env.PGCONNECT_TIMEOUT || 30,
502+
onnotice : o.onnotice,
503+
onparameter : o.onparameter,
504+
transform : Object.assign({}, o.transform),
504505
connection : Object.assign({ application_name: 'postgres.js' }, o.connection),
505-
debug : o.debug
506+
debug : o.debug
506507
},
507508
mergeUserTypes(o.types)
508509
)

tests/index.js

+28
Original file line numberDiff line numberDiff line change
@@ -937,3 +937,31 @@ t('Query parameters are not enumerable', async() => [
937937
-1,
938938
(await sql`selec ${ 1 }`.catch(err => Object.keys(err).indexOf('parameters')))
939939
])
940+
941+
t('connect_timeout throws proper error', async() => [
942+
'CONNECTION_CONNECT_TIMEOUT',
943+
await postgres({
944+
...options,
945+
...login_scram,
946+
connect_timeout: 0.001
947+
})`select 1`.catch(e => e.code)
948+
])
949+
950+
t('requests works after single connect_timeout', async() => {
951+
let first = true
952+
953+
const sql = postgres({
954+
...options,
955+
...login_scram,
956+
connect_timeout: { valueOf() { return first ? (first = false, 0.001) : 1 } }
957+
})
958+
959+
return [
960+
'CONNECTION_CONNECT_TIMEOUT,,1',
961+
[
962+
await sql`select 1 as x`.catch(x => x.code),
963+
await new Promise(r => setTimeout(r, 10)),
964+
(await sql`select 1 as x`)[0].x
965+
].join(',')
966+
]
967+
})

0 commit comments

Comments
 (0)