Skip to content

Commit da5112e

Browse files
committed
feat(cubestore-driver): improve WebSocket connection error messages
Add ConnectionError class to wrap WebSocket errors with CubeStore context, making it easier to diagnose connection failures.
1 parent fd8a312 commit da5112e

2 files changed

Lines changed: 35 additions & 9 deletions

File tree

packages/cubejs-cubestore-driver/src/WebSocketConnection.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { v4 as uuidv4 } from 'uuid';
44
import { InlineTable } from '@cubejs-backend/base-driver';
55
import { getEnv } from '@cubejs-backend/shared';
66
import { parseCubestoreResultMessage } from '@cubejs-backend/native';
7+
import { ConnectionError, QueryError } from './errors';
78
import {
89
HttpCommand,
910
HttpError,
@@ -24,9 +25,9 @@ export class WebSocketConnection {
2425

2526
protected webSocket: any;
2627

27-
private url: string;
28+
private readonly url: string;
2829

29-
private connectionId: string;
30+
private readonly connectionId: string;
3031

3132
public constructor(url: string) {
3233
this.url = url;
@@ -67,13 +68,18 @@ export class WebSocketConnection {
6768
webSocket.on('open', () => resolve(webSocket));
6869
webSocket.on('error', (err) => {
6970
this.currentConnectionTry += 1;
71+
7072
if (this.currentConnectionTry < this.maxConnectRetries) {
7173
setTimeout(async () => {
7274
resolve(this.initWebSocket());
7375
}, this.retryWaitTime());
7476
} else {
75-
reject(err);
77+
reject(new ConnectionError(
78+
`CubeStore connection failed after ${this.maxConnectRetries} retries: ${err.message}`,
79+
err
80+
));
7681
}
82+
7783
if (webSocket === this.webSocket) {
7884
this.webSocket = undefined;
7985
}
@@ -115,7 +121,7 @@ export class WebSocketConnection {
115121
const resolvers = webSocket.sentMessages[httpMessage.messageId()];
116122
delete webSocket.sentMessages[httpMessage.messageId()];
117123
if (!resolvers) {
118-
throw new Error(`Cube Store missed message id: ${httpMessage.messageId()}`); // logging
124+
throw new QueryError(`Cube Store missed message id: ${httpMessage.messageId()}`);
119125
}
120126

121127
if (getEnv('nativeOrchestrator') && msg.length > 1000) {
@@ -129,12 +135,12 @@ export class WebSocketConnection {
129135
const commandType = httpMessage.commandType();
130136

131137
if (commandType === HttpCommand.HttpError) {
132-
resolvers.reject(new Error(`${httpMessage.command(new HttpError())?.error()}`));
138+
resolvers.reject(new QueryError(`${httpMessage.command(new HttpError())?.error()}`));
133139
} else if (commandType === HttpCommand.HttpResultSet) {
134140
const resultSet = httpMessage.command(new HttpResultSet());
135141

136142
if (!resultSet) {
137-
resolvers.reject(new Error('Empty resultSet'));
143+
resolvers.reject(new QueryError('Empty resultSet'));
138144
return;
139145
}
140146

@@ -143,7 +149,7 @@ export class WebSocketConnection {
143149
for (let i = 0; i < columnsLen; i++) {
144150
const columnName = resultSet.columns(i);
145151
if (!columnName) {
146-
resolvers.reject(new Error('Column name is not defined'));
152+
resolvers.reject(new QueryError('Column name is not defined'));
147153
return;
148154
}
149155
columns.push(columnName);
@@ -154,7 +160,7 @@ export class WebSocketConnection {
154160
for (let i = 0; i < rowLen; i++) {
155161
const row = resultSet.rows(i);
156162
if (!row) {
157-
resolvers.reject(new Error('Null row'));
163+
resolvers.reject(new QueryError('Null row'));
158164
return;
159165
}
160166
const valueLen = row.valuesLength();
@@ -168,7 +174,7 @@ export class WebSocketConnection {
168174

169175
resolvers.resolve(result);
170176
} else {
171-
resolvers.reject(new Error('Unsupported command'));
177+
resolvers.reject(new QueryError('Unsupported command'));
172178
}
173179
}
174180
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
abstract class CubeStoreError extends Error {
2+
3+
}
4+
5+
export class ConnectionError extends CubeStoreError {
6+
public readonly cause?: Error;
7+
8+
public constructor(message: string, cause?: Error) {
9+
super(message);
10+
this.name = 'ConnectionError';
11+
this.cause = cause;
12+
}
13+
}
14+
15+
export class QueryError extends CubeStoreError {
16+
public constructor(message: string) {
17+
super(message);
18+
this.name = 'QueryError';
19+
}
20+
}

0 commit comments

Comments
 (0)