Skip to content

Commit 94723d3

Browse files
author
Daniele Briggi
committed
fix(connection): improve connection management
- resolve the creation of two connections. The dynamic import of the connection modules delayed the initialization of the SQLiteCloudConnection object. Between the initialization of the Database object and the call to sql() method, the connection was not yet initialized - connection to the database and the commands are put in queue to ensure the connection to be ready (the socket connection is a background operation) - remove the implicit connection to the database in the sql() methods. We want the user be aware of the status of the connection (eg, due to open transactions) - enable TCP keep alive to be notified of the most of the cases of errors on the TCP socket
1 parent 717b862 commit 94723d3

8 files changed

+190
-168
lines changed

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sqlitecloud/drivers",
3-
"version": "1.0.417",
3+
"version": "1.0.421",
44
"description": "SQLiteCloud drivers for Typescript/Javascript in edge, web and node clients",
55
"main": "./lib/index.js",
66
"types": "./lib/index.d.ts",

src/drivers/connection-tls.ts

+17-8
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
* connection-tls.ts - connection via tls socket and sqlitecloud protocol
33
*/
44

5-
import { type SQLiteCloudConfig, SQLiteCloudError, type ErrorCallback, type ResultsCallback, SQLiteCloudCommand } from './types'
65
import { SQLiteCloudConnection } from './connection'
7-
import { getInitializationCommands } from './utilities'
86
import {
7+
bufferEndsWith,
8+
CMD_COMPRESSED,
9+
CMD_ROWSET_CHUNK,
10+
decompressBuffer,
911
formatCommand,
1012
hasCommandLength,
1113
parseCommandLength,
12-
popData,
13-
decompressBuffer,
1414
parseRowsetChunks,
15-
CMD_COMPRESSED,
16-
CMD_ROWSET_CHUNK,
17-
bufferEndsWith,
15+
popData,
1816
ROWSET_CHUNKS_END
1917
} from './protocol'
18+
import { type ErrorCallback, type ResultsCallback, SQLiteCloudCommand, type SQLiteCloudConfig, SQLiteCloudError } from './types'
19+
import { getInitializationCommands } from './utilities'
2020

2121
// explicitly importing buffer library to allow cross-platform support by replacing it
2222
import { Buffer } from 'buffer'
@@ -77,6 +77,10 @@ export class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
7777
callback?.call(this, error)
7878
})
7979
})
80+
this.socket.setKeepAlive(true)
81+
// disable Nagle algorithm because we want our writes to be sent ASAP
82+
// https://brooker.co.za/blog/2024/05/09/nagle.html
83+
this.socket.setNoDelay(true)
8084

8185
this.socket.on('data', data => {
8286
this.processCommandsData(data)
@@ -97,6 +101,11 @@ export class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
97101
this.processCommandsFinish(new SQLiteCloudError('Connection closed', { errorCode: 'ERR_CONNECTION_CLOSED' }))
98102
})
99103

104+
this.socket.on('timeout', () => {
105+
this.close()
106+
this.processCommandsFinish(new SQLiteCloudError('Connection ened due to timeout', { errorCode: 'ERR_CONNECTION_TIMEOUT' }))
107+
})
108+
100109
return this
101110
}
102111

@@ -241,7 +250,7 @@ export class SQLiteCloudTlsConnection extends SQLiteCloudConnection {
241250
}
242251

243252
/** Disconnect immediately, release connection, no events. */
244-
close(): this {
253+
public close(): this {
245254
if (this.socket) {
246255
this.socket.removeAllListeners()
247256
this.socket.destroy()

src/drivers/connection-ws.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
* transport-ws.ts - handles low level communication with sqlitecloud server via socket.io websocket
33
*/
44

5-
import { SQLiteCloudConfig, SQLiteCloudError, ErrorCallback, ResultsCallback, SQLiteCloudCommand, SQLiteCloudDataTypes } from './types'
6-
import { SQLiteCloudRowset } from './rowset'
7-
import { SQLiteCloudConnection } from './connection'
85
import { io, Socket } from 'socket.io-client'
6+
import { SQLiteCloudConnection } from './connection'
7+
import { SQLiteCloudRowset } from './rowset'
8+
import { ErrorCallback, ResultsCallback, SQLiteCloudCommand, SQLiteCloudConfig, SQLiteCloudError } from './types'
99

1010
/**
1111
* Implementation of TransportConnection that connects to the database indirectly
@@ -19,7 +19,7 @@ export class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
1919

2020
/** True if connection is open */
2121
get connected(): boolean {
22-
return !!this.socket
22+
return !!(this.socket && this.socket?.connected)
2323
}
2424

2525
/* Opens a connection with the server and sends the initialization commands. Will throw in case of errors. */
@@ -32,11 +32,25 @@ export class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
3232
const connectionstring = this.config.connectionstring as string
3333
const gatewayUrl = this.config?.gatewayurl || `${this.config.host === 'localhost' ? 'ws' : 'wss'}://${this.config.host as string}:4000`
3434
this.socket = io(gatewayUrl, { auth: { token: connectionstring } })
35+
36+
this.socket.on('connect', () => {
37+
callback?.call(this, null)
38+
})
39+
40+
this.socket.on('disconnect', (reason) => {
41+
this.close()
42+
callback?.call(this, new SQLiteCloudError('Disconnected', { errorCode: 'ERR_CONNECTION_DISCONNECTED', cause: reason }))
43+
})
44+
45+
this.socket.on('error', (error: Error) => {
46+
this.close()
47+
callback?.call(this, new SQLiteCloudError('Connection error', { errorCode: 'ERR_CONNECTION_ERROR', cause: error }))
48+
})
3549
}
36-
callback?.call(this, null)
3750
} catch (error) {
3851
callback?.call(this, error as Error)
3952
}
53+
4054
return this
4155
}
4256

@@ -78,11 +92,12 @@ export class SQLiteCloudWebsocketConnection extends SQLiteCloudConnection {
7892
public close(): this {
7993
console.assert(this.socket !== null, 'SQLiteCloudWebsocketConnection.close - connection already closed')
8094
if (this.socket) {
95+
this.socket?.removeAllListeners()
8196
this.socket?.close()
8297
this.socket = undefined
8398
}
99+
84100
this.operations.clear()
85-
this.socket = undefined
86101
return this
87102
}
88103
}

0 commit comments

Comments
 (0)