@lightdash/warehouses 2.128.1 → 2.130.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const HiveDriverError_1 = __importDefault(require("@databricks/sql/dist/errors/HiveDriverError"));
40
+ const OperationStateError_1 = __importStar(require("@databricks/sql/dist/errors/OperationStateError"));
41
+ const StatusError_1 = __importDefault(require("@databricks/sql/dist/errors/StatusError"));
42
+ const TCLIService_types_1 = require("@databricks/sql/thrift/TCLIService_types");
43
+ const DatabricksWarehouseStartupRetry_1 = require("./DatabricksWarehouseStartupRetry");
44
+ const statusError = (errorMessage) => new StatusError_1.default({ statusCode: TCLIService_types_1.TStatusCode.ERROR_STATUS, errorMessage });
45
+ const sessionHandleError = statusError('requirement failed: Session handle: SessionHandle [01f19fd1-ac81-1e09-bb7c-357018ed26f1] has not been initialized or had already closed.');
46
+ const diskDirectoryError = statusError("Couldn't create directory /local_disk0/tmp/a1b2c3d4-0000-1111-2222-333344445555/_resources");
47
+ const warehouseStartingError = statusError('SQL warehouse xyz is not ready to accept connections (current state: STARTING)');
48
+ // Pro/classic warehouse in STARTING: 503s until the driver's own HTTP retries give up
49
+ const driverRetriesExhaustedError = new HiveDriverError_1.default('Hive driver: 503 when connecting to resource. Max retry count exceeded.');
50
+ describe('isDatabricksWarehouseStartingError', () => {
51
+ it('matches the errors Databricks returns while a SQL warehouse is stopped or starting', () => {
52
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(sessionHandleError)).toBe(true);
53
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(diskDirectoryError)).toBe(true);
54
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(warehouseStartingError)).toBe(true);
55
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(driverRetriesExhaustedError)).toBe(true);
56
+ });
57
+ it('does not match other HTTP failures the driver gave up on', () => {
58
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(new HiveDriverError_1.default('Hive driver: 500 when connecting to resource. Max retry count exceeded.'))).toBe(false);
59
+ });
60
+ it('matches the same messages when the operation fails during polling', () => {
61
+ const error = new OperationStateError_1.default(OperationStateError_1.OperationStateErrorCode.Error, {
62
+ displayMessage: diskDirectoryError.message,
63
+ });
64
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(error)).toBe(true);
65
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(new OperationStateError_1.default(OperationStateError_1.OperationStateErrorCode.Timeout))).toBe(false);
66
+ });
67
+ it('does not match SQL, permission or auth failures', () => {
68
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(statusError('[PARSE_SYNTAX_ERROR] Syntax error at or near FROM'))).toBe(false);
69
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(statusError('PERMISSION_DENIED: User does not have USE SCHEMA on Schema'))).toBe(false);
70
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(new Error('Request failed with status 401: Unauthorized'))).toBe(false);
71
+ });
72
+ it('only matches driver status errors, not other errors with the same text', () => {
73
+ expect((0, DatabricksWarehouseStartupRetry_1.isDatabricksWarehouseStartingError)(new Error(sessionHandleError.message))).toBe(false);
74
+ });
75
+ });
76
+ describe('getDatabricksWarehouseStartupRetryDelayMs', () => {
77
+ it('backs off exponentially from 2s, capped at 30s', () => {
78
+ const delays = [1, 2, 3, 4, 5, 6].map((attempt) => (0, DatabricksWarehouseStartupRetry_1.getDatabricksWarehouseStartupRetryDelayMs)(attempt, 0));
79
+ expect(delays).toEqual([2000, 4000, 8000, 16000, 30000, 30000]);
80
+ });
81
+ it('stops once the next wait would pass the deadline', () => {
82
+ const { deadlineMs } = DatabricksWarehouseStartupRetry_1.DATABRICKS_WAREHOUSE_STARTUP_RETRY;
83
+ expect((0, DatabricksWarehouseStartupRetry_1.getDatabricksWarehouseStartupRetryDelayMs)(9, deadlineMs - 30000)).toBe(30000);
84
+ expect((0, DatabricksWarehouseStartupRetry_1.getDatabricksWarehouseStartupRetryDelayMs)(9, deadlineMs - 29999)).toBeNull();
85
+ });
86
+ });
87
+ describe('DatabricksWarehouseStartupRetry', () => {
88
+ beforeEach(() => {
89
+ vi.useFakeTimers();
90
+ vi.spyOn(console, 'warn').mockImplementation(() => { });
91
+ });
92
+ afterEach(() => {
93
+ vi.useRealTimers();
94
+ vi.restoreAllMocks();
95
+ });
96
+ // Drains the backoff timer so the wait resolves under fake timers
97
+ const waitBeforeRetry = async (retry, error) => {
98
+ const result = retry.waitBeforeRetry(error);
99
+ await vi.runAllTimersAsync();
100
+ return result;
101
+ };
102
+ it('waits with backoff before retrying a warehouse startup error', async () => {
103
+ const retry = new DatabricksWarehouseStartupRetry_1.DatabricksWarehouseStartupRetry();
104
+ const start = Date.now();
105
+ await expect(waitBeforeRetry(retry, sessionHandleError)).resolves.toBe(true);
106
+ expect(Date.now() - start).toBe(2000);
107
+ await expect(waitBeforeRetry(retry, diskDirectoryError)).resolves.toBe(true);
108
+ expect(Date.now() - start).toBe(6000);
109
+ expect(console.warn).toHaveBeenCalledTimes(2);
110
+ expect(vi.mocked(console.warn).mock.calls[0][0]).toContain('has not been initialized');
111
+ });
112
+ it('does not wait for errors that are not warehouse startup errors', async () => {
113
+ const retry = new DatabricksWarehouseStartupRetry_1.DatabricksWarehouseStartupRetry();
114
+ await expect(retry.waitBeforeRetry(statusError('Syntax error near FROM'))).resolves.toBe(false);
115
+ expect(vi.getTimerCount()).toBe(0);
116
+ });
117
+ it('counts time spent outside the wait against the deadline', async () => {
118
+ const retry = new DatabricksWarehouseStartupRetry_1.DatabricksWarehouseStartupRetry();
119
+ const start = Date.now();
120
+ let retries = 0;
121
+ // eslint-disable-next-line no-await-in-loop
122
+ while (await waitBeforeRetry(retry, sessionHandleError)) {
123
+ retries += 1;
124
+ vi.advanceTimersByTime(31000); // the driver's own HTTP retries per attempt
125
+ }
126
+ expect(retries).toBe(11);
127
+ expect(Date.now() - start).toBeLessThanOrEqual(DatabricksWarehouseStartupRetry_1.DATABRICKS_WAREHOUSE_STARTUP_RETRY.deadlineMs + 31000);
128
+ });
129
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/warehouses",
3
- "version": "2.128.1",
3
+ "version": "2.130.0",
4
4
  "description": "Warehouse connectors for Lightdash",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "snowflake-sdk": "2.3.4",
29
29
  "ssh2": "1.14.0",
30
30
  "trino-client": "0.2.9",
31
- "@lightdash/common": "2.128.1"
31
+ "@lightdash/common": "2.130.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "oxlint": "1.75.0",