-
Notifications
You must be signed in to change notification settings - Fork 30
/
ping.ts
107 lines (100 loc) · 3.53 KB
/
ping.ts
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
import type { PingResult } from '@clickhouse/client'
import { createClient } from '@clickhouse/client' // or '@clickhouse/client-web'
import http from 'http'
/**
* This example assumes that you have a ClickHouse server running locally
* (for example, from our root docker-compose.yml file),
* and your local ports 8100 and 18123 are free.
*
* Illustrates various ping operation results and how these might be handled on the application side.
* Ping might be a useful tool to check if the server is available when the application starts,
* especially with ClickHouse Cloud, where an instance might be idling and will wake up after a ping.
*/
void (async () => {
await existingHostPing()
await nonExistingHostPing()
await timeoutPing()
})()
async function existingHostPing() {
const client = createClient({
host: process.env['CLICKHOUSE_HOST'], // defaults to 'http://localhost:8123'
password: process.env['CLICKHOUSE_PASSWORD'], // defaults to an empty string
})
const pingResult = await client.ping()
if (pingResult.success) {
console.info('[ExistingHostPing] Ping to the existing host is successful')
} else {
console.error(
'[ExistingHostPing] Ping expected to succeed, but got:',
pingResult,
)
}
await client.close()
}
async function nonExistingHostPing() {
const client = createClient({
host: 'http://localhost:8100', // non-existing host
request_timeout: 50, // low request_timeout to speed up the example
})
// Ping does not throw an error; instead, { success: false; error: Error } is returned.
const pingResult = await client.ping()
if (hasConnectionRefusedError(pingResult)) {
console.info('[NonExistingHostPing] Ping connection refused, as expected')
} else {
console.error(
'[NonExistingHostPing] Ping expected to fail with ECONNREFUSED, but got:',
pingResult,
)
}
await client.close()
}
// Using a "slow" HTTP server to simulate a ClickHouse server that does not respond to the request in time
async function timeoutPing() {
const server = startSlowHTTPServer()
const client = createClient({
host: 'http://localhost:18123',
request_timeout: 50, // low request_timeout to speed up the example
})
// Ping does not throw an error; instead, { success: false; error: Error } is returned.
const pingResult = await client.ping()
server.close()
// If your application uses ping during its startup, you could retry a failed ping a few times.
// Maybe it's a transient network issue or, in case of ClickHouse Cloud,
// the instance is idling and will start waking up after a ping.
if (hasTimeoutError(pingResult)) {
console.info('[TimeoutPing] Ping timed out, as expected')
} else {
console.error(
'[TimeoutPing] Ping expected to fail with a timeout error, but got:',
pingResult,
)
}
await client.close()
}
function startSlowHTTPServer() {
const server = http.createServer(async (_req, res) => {
await new Promise((resolve) => setTimeout(resolve, 100))
res.write('Ok.')
return res.end()
})
server.listen(18123)
return server
}
function hasConnectionRefusedError(
pingResult: PingResult,
): pingResult is PingResult & { error: { code: 'ECONNREFUSED' } } {
return (
!pingResult.success &&
'code' in pingResult.error &&
pingResult.error.code === 'ECONNREFUSED'
)
}
function hasTimeoutError(
pingResult: PingResult,
): pingResult is PingResult & { error: Error } {
return (
!pingResult.success &&
'message' in pingResult.error &&
pingResult.error.message.includes('Timeout error')
)
}