Skip to content

Commit

Permalink
handle connection errors @ MssqlDriver. (#1042)
Browse files Browse the repository at this point in the history
  • Loading branch information
igalklebanov authored Jun 18, 2024
1 parent 87f365e commit fb5bf4d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 16 deletions.
20 changes: 12 additions & 8 deletions src/dialect/mssql/mssql-dialect-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,26 @@ export interface TediousConnection {
name?: string,
isolationLevel?: number,
): void
cancel(): boolean
close(): void
commitTransaction(
callback: (error?: Error | null) => void,
name?: string,
): void
connect(callback?: (error?: Error) => void): void
execSql(request: TediousRequest): void
off(event: 'error', listener: (error: unknown) => void): this
off(event: string, listener: (...args: any[]) => void): this
on(event: 'error', listener: (error: unknown) => void): this
on(event: string, listener: (...args: any[]) => void): this
once(event: 'end', listener: () => void): this
once(event: string, listener: (...args: any[]) => void): this
reset(callback: (error?: Error | null) => void): void
rollbackTransaction(
callback: (error?: Error | null) => void,
name?: string,
): void
saveTransaction(callback: (error?: Error | null) => void, name: string): void
cancel(): boolean
reset(callback: (error?: Error | null) => void): void
close(): void
once(event: 'end', listener: () => void): this
once(event: string, listener: (...args: any[]) => void): this
connect(callback?: (error?: Error) => void): void
}

export type TediousIsolationLevel = Record<string, number>
Expand All @@ -104,12 +108,12 @@ export declare class TediousRequest {
scale?: number
}> | null,
): void
off(event: 'row', listener: (columns: any) => void): this
off(event: string, listener: (...args: any[]) => void): this
on(event: 'row', listener: (columns: any) => void): this
on(event: string, listener: (...args: any[]) => void): this
once(event: 'requestCompleted', listener: () => void): this
once(event: string, listener: (...args: any[]) => void): this
off(event: 'row', listener: (columns: any) => void): this
off(event: string, listener: (...args: any[]) => void): this
pause(): void
resume(): void
}
Expand Down
32 changes: 24 additions & 8 deletions src/dialect/mssql/mssql-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,10 @@ export class MssqlDriver implements Driver {
create: async () => {
const connection = await this.#config.tedious.connectionFactory()

await new Promise((resolve, reject) =>
connection.connect((error) => {
if (error) reject(error)
else resolve(undefined)
}),
)

return new MssqlConnection(connection, this.#config.tedious)
return await new MssqlConnection(
connection,
this.#config.tedious,
).connect()
},
destroy: async (connection) => {
await connection[PRIVATE_DESTROY_METHOD]()
Expand Down Expand Up @@ -104,6 +100,11 @@ class MssqlConnection implements DatabaseConnection {
constructor(connection: TediousConnection, tedious: Tedious) {
this.#connection = connection
this.#tedious = tedious

this.#connection.on('error', console.error)
this.#connection.once('end', () => {
this.#connection.off('error', console.error)
})
}

async beginTransaction(settings: TransactionSettings): Promise<void> {
Expand Down Expand Up @@ -132,6 +133,21 @@ class MssqlConnection implements DatabaseConnection {
)
}

async connect(): Promise<this> {
await new Promise((resolve, reject) => {
this.#connection.connect((error) => {
if (error) {
console.error(error)
reject(error)
} else {
resolve(undefined)
}
})
})

return this
}

async executeQuery<O>(compiledQuery: CompiledQuery): Promise<QueryResult<O>> {
try {
const deferred = new Deferred<OnDone<O>>()
Expand Down
52 changes: 52 additions & 0 deletions test/node/src/disconnects.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Kysely, MssqlDialect, sql } from '../../..'
import { DIALECTS, DIALECT_CONFIGS, Database, expect } from './test-setup'
import * as tarn from 'tarn'
import * as tedious from 'tedious'

const dialect = 'mssql'

if (DIALECTS.includes(dialect)) {
describe(`${dialect}: disconnects`, () => {
let connection: tedious.Connection
let connectionFactoryTimesCalled = 0
let db: Kysely<Database>

before(async () => {
db = new Kysely({
dialect: new MssqlDialect({
tarn: {
...tarn,
options: {
min: 0,
max: 1,
},
},
tedious: {
...tedious,
connectionFactory: () => {
connectionFactoryTimesCalled++

return (connection = new tedious.Connection(
DIALECT_CONFIGS[dialect],
))
},
},
}),
})
})

after(async () => {
await db.destroy()
})

it('should be disconnection tolerant', async () => {
await sql`select 1`.execute(db)
expect(connectionFactoryTimesCalled).to.equal(1)

connection.socketError(new Error('moshe'))

await sql`select 1`.execute(db)
expect(connectionFactoryTimesCalled).to.equal(2)
})
})
}

0 comments on commit fb5bf4d

Please sign in to comment.