@oneuptime/common 11.3.2 → 11.3.3
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.
- package/Server/Infrastructure/ClickhouseConfig.ts +21 -0
- package/Server/Infrastructure/ClickhouseDatabase.ts +12 -0
- package/Server/Services/AnalyticsDatabaseService.ts +79 -4
- package/Tests/UI/Components/Pill.test.tsx +3 -1
- package/UI/Components/EditionLabel/EditionLabel.tsx +6 -1
- package/UI/Components/Footer/Footer.tsx +1 -1
- package/UI/Components/Icon/Icon.tsx +13 -1
- package/UI/Components/Image/Image.tsx +6 -1
- package/UI/Components/Link/Link.tsx +22 -0
- package/UI/Components/MasterPage/MasterPage.tsx +30 -1
- package/UI/Components/Page/Page.tsx +29 -2
- package/UI/Components/Pagination/Pagination.tsx +110 -180
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +17 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +10 -1
- package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +59 -8
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +2 -2
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Image/Image.js +8 -1
- package/build/dist/UI/Components/Image/Image.js.map +1 -1
- package/build/dist/UI/Components/Link/Link.js +9 -0
- package/build/dist/UI/Components/Link/Link.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +2 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +24 -1
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +44 -94
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/package.json +1 -1
|
@@ -133,116 +133,81 @@ const Pagination: FunctionComponent<ComponentProps> = (
|
|
|
133
133
|
/>
|
|
134
134
|
</div>
|
|
135
135
|
|
|
136
|
-
<ul className="py-3" role="list">
|
|
137
|
-
<li
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
let currentPageNumber: number = props.currentPageNumber;
|
|
144
|
-
|
|
145
|
-
if (typeof currentPageNumber === "string") {
|
|
146
|
-
currentPageNumber = parseInt(currentPageNumber);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (props.onNavigateToPage && !isPreviousDisabled) {
|
|
150
|
-
props.onNavigateToPage(
|
|
151
|
-
currentPageNumber - 1,
|
|
152
|
-
props.itemsOnPage,
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
}}
|
|
156
|
-
onKeyDown={(e: React.KeyboardEvent) => {
|
|
157
|
-
if (
|
|
158
|
-
(e.key === "Enter" || e.key === " ") &&
|
|
159
|
-
!isPreviousDisabled
|
|
160
|
-
) {
|
|
161
|
-
e.preventDefault();
|
|
136
|
+
<ul className="flex py-3" role="list">
|
|
137
|
+
<li className="flex">
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
disabled={isPreviousDisabled}
|
|
141
|
+
aria-label="Go to previous page"
|
|
142
|
+
onClick={() => {
|
|
162
143
|
let currentPageNumber: number = props.currentPageNumber;
|
|
144
|
+
|
|
163
145
|
if (typeof currentPageNumber === "string") {
|
|
164
146
|
currentPageNumber = parseInt(currentPageNumber);
|
|
165
147
|
}
|
|
166
|
-
|
|
148
|
+
|
|
149
|
+
if (props.onNavigateToPage && !isPreviousDisabled) {
|
|
167
150
|
props.onNavigateToPage(
|
|
168
151
|
currentPageNumber - 1,
|
|
169
152
|
props.itemsOnPage,
|
|
170
153
|
);
|
|
171
154
|
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
155
|
+
}}
|
|
156
|
+
className={` inline-flex items-center rounded-l-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
157
|
+
isPreviousDisabled
|
|
158
|
+
? "bg-gray-100 cursor-not-allowed"
|
|
159
|
+
: "hover:bg-gray-50 cursor-pointer"
|
|
160
|
+
}`}
|
|
161
|
+
>
|
|
162
|
+
<span className="page-link">Previous</span>
|
|
163
|
+
</button>
|
|
181
164
|
</li>
|
|
182
|
-
<li
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
}}
|
|
202
|
-
>
|
|
203
|
-
<span>{props.currentPageNumber}</span>
|
|
165
|
+
<li className="flex">
|
|
166
|
+
<button
|
|
167
|
+
type="button"
|
|
168
|
+
disabled={isCurrentPageButtonDisabled}
|
|
169
|
+
aria-current="page"
|
|
170
|
+
aria-label={`Page ${props.currentPageNumber}, current page. Select to jump to another page.`}
|
|
171
|
+
data-testid="current-page-link"
|
|
172
|
+
className={` z-10 inline-flex items-center border border-x-0 border-gray-300 hover:bg-gray-50 px-4 py-2 text-sm font-medium text-text-600 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
173
|
+
isCurrentPageButtonDisabled ? "bg-gray-100" : ""
|
|
174
|
+
}`}
|
|
175
|
+
onClick={() => {
|
|
176
|
+
if (!isHasMoreMode) {
|
|
177
|
+
setShowPaginationModel(true);
|
|
178
|
+
}
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
<span>{props.currentPageNumber}</span>
|
|
182
|
+
</button>
|
|
204
183
|
</li>
|
|
205
|
-
<li
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
let currentPageNumber: number = props.currentPageNumber;
|
|
212
|
-
|
|
213
|
-
if (typeof currentPageNumber === "string") {
|
|
214
|
-
currentPageNumber = parseInt(currentPageNumber);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (props.onNavigateToPage && !isNextDisabled) {
|
|
218
|
-
props.onNavigateToPage(
|
|
219
|
-
currentPageNumber + 1,
|
|
220
|
-
props.itemsOnPage,
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}}
|
|
224
|
-
onKeyDown={(e: React.KeyboardEvent) => {
|
|
225
|
-
if ((e.key === "Enter" || e.key === " ") && !isNextDisabled) {
|
|
226
|
-
e.preventDefault();
|
|
184
|
+
<li className="flex">
|
|
185
|
+
<button
|
|
186
|
+
type="button"
|
|
187
|
+
disabled={isNextDisabled}
|
|
188
|
+
aria-label="Go to next page"
|
|
189
|
+
onClick={() => {
|
|
227
190
|
let currentPageNumber: number = props.currentPageNumber;
|
|
191
|
+
|
|
228
192
|
if (typeof currentPageNumber === "string") {
|
|
229
193
|
currentPageNumber = parseInt(currentPageNumber);
|
|
230
194
|
}
|
|
231
|
-
|
|
195
|
+
|
|
196
|
+
if (props.onNavigateToPage && !isNextDisabled) {
|
|
232
197
|
props.onNavigateToPage(
|
|
233
198
|
currentPageNumber + 1,
|
|
234
199
|
props.itemsOnPage,
|
|
235
200
|
);
|
|
236
201
|
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
202
|
+
}}
|
|
203
|
+
className={` inline-flex items-center rounded-r-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
204
|
+
isNextDisabled
|
|
205
|
+
? "bg-gray-100 cursor-not-allowed"
|
|
206
|
+
: " hover:bg-gray-50 cursor-pointer"
|
|
207
|
+
}`}
|
|
208
|
+
>
|
|
209
|
+
<span>Next</span>
|
|
210
|
+
</button>
|
|
246
211
|
</li>
|
|
247
212
|
</ul>
|
|
248
213
|
</div>
|
|
@@ -265,116 +230,81 @@ const Pagination: FunctionComponent<ComponentProps> = (
|
|
|
265
230
|
|
|
266
231
|
<div className="md:hidden">
|
|
267
232
|
<div className="inline-flex -space-x-px rounded-md shadow-sm">
|
|
268
|
-
<ul role="list">
|
|
269
|
-
<li
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
let currentPageNumber: number = props.currentPageNumber;
|
|
276
|
-
|
|
277
|
-
if (typeof currentPageNumber === "string") {
|
|
278
|
-
currentPageNumber = parseInt(currentPageNumber);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (props.onNavigateToPage && !isPreviousDisabled) {
|
|
282
|
-
props.onNavigateToPage(
|
|
283
|
-
currentPageNumber - 1,
|
|
284
|
-
props.itemsOnPage,
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}}
|
|
288
|
-
onKeyDown={(e: React.KeyboardEvent) => {
|
|
289
|
-
if (
|
|
290
|
-
(e.key === "Enter" || e.key === " ") &&
|
|
291
|
-
!isPreviousDisabled
|
|
292
|
-
) {
|
|
293
|
-
e.preventDefault();
|
|
233
|
+
<ul className="flex" role="list">
|
|
234
|
+
<li className="flex">
|
|
235
|
+
<button
|
|
236
|
+
type="button"
|
|
237
|
+
disabled={isPreviousDisabled}
|
|
238
|
+
aria-label="Go to previous page"
|
|
239
|
+
onClick={() => {
|
|
294
240
|
let currentPageNumber: number = props.currentPageNumber;
|
|
241
|
+
|
|
295
242
|
if (typeof currentPageNumber === "string") {
|
|
296
243
|
currentPageNumber = parseInt(currentPageNumber);
|
|
297
244
|
}
|
|
298
|
-
|
|
245
|
+
|
|
246
|
+
if (props.onNavigateToPage && !isPreviousDisabled) {
|
|
299
247
|
props.onNavigateToPage(
|
|
300
248
|
currentPageNumber - 1,
|
|
301
249
|
props.itemsOnPage,
|
|
302
250
|
);
|
|
303
251
|
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
252
|
+
}}
|
|
253
|
+
className={` inline-flex items-center rounded-l-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
254
|
+
isPreviousDisabled
|
|
255
|
+
? "bg-gray-100 cursor-not-allowed"
|
|
256
|
+
: "hover:bg-gray-50 cursor-pointer"
|
|
257
|
+
}`}
|
|
258
|
+
>
|
|
259
|
+
<span className="page-link">Previous</span>
|
|
260
|
+
</button>
|
|
313
261
|
</li>
|
|
314
|
-
<li
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
}}
|
|
334
|
-
>
|
|
335
|
-
<span>{props.currentPageNumber}</span>
|
|
262
|
+
<li className="flex">
|
|
263
|
+
<button
|
|
264
|
+
type="button"
|
|
265
|
+
disabled={isCurrentPageButtonDisabled}
|
|
266
|
+
aria-current="page"
|
|
267
|
+
aria-label={`Page ${props.currentPageNumber}, current page. Select to jump to another page.`}
|
|
268
|
+
data-testid="current-page-link-mobile"
|
|
269
|
+
className={` z-10 inline-flex items-center border border-x-0 border-gray-300 hover:bg-gray-50 px-4 py-2 text-sm font-medium text-text-600 cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
270
|
+
isCurrentPageButtonDisabled ? "bg-gray-100" : ""
|
|
271
|
+
}`}
|
|
272
|
+
onClick={() => {
|
|
273
|
+
if (!isHasMoreMode) {
|
|
274
|
+
setShowPaginationModel(true);
|
|
275
|
+
}
|
|
276
|
+
}}
|
|
277
|
+
>
|
|
278
|
+
<span>{props.currentPageNumber}</span>
|
|
279
|
+
</button>
|
|
336
280
|
</li>
|
|
337
|
-
<li
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
let currentPageNumber: number = props.currentPageNumber;
|
|
344
|
-
|
|
345
|
-
if (typeof currentPageNumber === "string") {
|
|
346
|
-
currentPageNumber = parseInt(currentPageNumber);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (props.onNavigateToPage && !isNextDisabled) {
|
|
350
|
-
props.onNavigateToPage(
|
|
351
|
-
currentPageNumber + 1,
|
|
352
|
-
props.itemsOnPage,
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
}}
|
|
356
|
-
onKeyDown={(e: React.KeyboardEvent) => {
|
|
357
|
-
if ((e.key === "Enter" || e.key === " ") && !isNextDisabled) {
|
|
358
|
-
e.preventDefault();
|
|
281
|
+
<li className="flex">
|
|
282
|
+
<button
|
|
283
|
+
type="button"
|
|
284
|
+
disabled={isNextDisabled}
|
|
285
|
+
aria-label="Go to next page"
|
|
286
|
+
onClick={() => {
|
|
359
287
|
let currentPageNumber: number = props.currentPageNumber;
|
|
288
|
+
|
|
360
289
|
if (typeof currentPageNumber === "string") {
|
|
361
290
|
currentPageNumber = parseInt(currentPageNumber);
|
|
362
291
|
}
|
|
363
|
-
|
|
292
|
+
|
|
293
|
+
if (props.onNavigateToPage && !isNextDisabled) {
|
|
364
294
|
props.onNavigateToPage(
|
|
365
295
|
currentPageNumber + 1,
|
|
366
296
|
props.itemsOnPage,
|
|
367
297
|
);
|
|
368
298
|
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
299
|
+
}}
|
|
300
|
+
className={` inline-flex items-center rounded-r-md border border-gray-300 bg-white px-2 py-2 text-sm font-medium text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500 ${
|
|
301
|
+
isNextDisabled
|
|
302
|
+
? "bg-gray-100 cursor-not-allowed"
|
|
303
|
+
: " hover:bg-gray-50 cursor-pointer"
|
|
304
|
+
}`}
|
|
305
|
+
>
|
|
306
|
+
<span>Next</span>
|
|
307
|
+
</button>
|
|
378
308
|
</li>
|
|
379
309
|
</ul>
|
|
380
310
|
</div>
|
|
@@ -70,5 +70,22 @@ if (ShouldClickhouseSslEnable &&
|
|
|
70
70
|
}
|
|
71
71
|
export const dataSourceOptions = options;
|
|
72
72
|
export const ingestDataSourceOptions = Object.assign(Object.assign({}, options), { max_open_connections: MaxClickhouseIngestConnections });
|
|
73
|
+
/*
|
|
74
|
+
* Dedicated pool for schema sync + data migrations. The 58s request_timeout
|
|
75
|
+
* above is a socket *idle* timer (see the note on request_timeout) sized for
|
|
76
|
+
* dashboard reads sitting behind nginx's 60s proxy_read_timeout. Migrations
|
|
77
|
+
* do NOT go through nginx (the app connects straight to clickhouse:8123), and
|
|
78
|
+
* a single migration statement — an ON CLUSTER DDL, an MV / projection
|
|
79
|
+
* rebuild, or a type/codec-rewrite MODIFY COLUMN on a multi-billion-row
|
|
80
|
+
* telemetry table — can legitimately stream zero bytes for many minutes,
|
|
81
|
+
* which the 58s idle timer would destroy mid-flight ("Timeout error.") and
|
|
82
|
+
* crash the boot process. Give migrations a much higher idle ceiling. It is
|
|
83
|
+
* finite (not 0) on purpose: a genuinely dead connection / network black hole
|
|
84
|
+
* must still fail eventually rather than hang forever. Long statements should
|
|
85
|
+
* additionally carry send_progress_in_http_headers (see MigrationExecuteOptions
|
|
86
|
+
* in AnalyticsDatabaseService) so the socket stays non-idle, and a server-side
|
|
87
|
+
* SETTINGS max_execution_time so ClickHouse remains the authoritative cap.
|
|
88
|
+
*/
|
|
89
|
+
export const migrationDataSourceOptions = Object.assign(Object.assign({}, options), { request_timeout: 30 * 60 * 1000 });
|
|
73
90
|
export const testDataSourceOptions = dataSourceOptions;
|
|
74
91
|
//# sourceMappingURL=ClickhouseConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClickhouseConfig.js","sourceRoot":"","sources":["../../../../Server/Infrastructure/ClickhouseConfig.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAIhD,MAAM,YAAY,GAAW,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAEtE,MAAM,cAAc,GAAa,cAAc,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC9E,MAAM,cAAc,GAAW,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAEnE,MAAM,OAAO,GAAkC;IAC7C,GAAG,EAAE,GAAG,YAAY,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,cAAc,EAAE;IACvE,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,WAAW,EAAE,WAAW;IACxB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,EAAE,KAAM;IACvB;;;;;OAKG;IACH,oBAAoB,EAAE,wBAAwB;IAC9C;;;;;;;;;;OAUG;IACH,WAAW,EAAE;QACX,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAEF,IAAI,yBAAyB,IAAI,eAAe,EAAE,CAAC;IACjD,OAAO,CAAC,GAAG,GAAG;QACZ,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,IACE,yBAAyB;IACzB,eAAe;IACf,iBAAiB;IACjB,gBAAgB,EAChB,CAAC;IACD,OAAO,CAAC,GAAG,GAAG;QACZ,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;QACrC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAkC,OAAO,CAAC;AAExE,MAAM,CAAC,MAAM,uBAAuB,mCAC/B,OAAO,KACV,oBAAoB,EAAE,8BAA8B,GACrD,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAChC,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"ClickhouseConfig.js","sourceRoot":"","sources":["../../../../Server/Infrastructure/ClickhouseConfig.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,QAAQ,MAAM,0BAA0B,CAAC;AAIhD,MAAM,YAAY,GAAW,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAEtE,MAAM,cAAc,GAAa,cAAc,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC9E,MAAM,cAAc,GAAW,CAAC,cAAc,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAEnE,MAAM,OAAO,GAAkC;IAC7C,GAAG,EAAE,GAAG,YAAY,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,cAAc,EAAE;IACvE,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,QAAQ,EAAE,kBAAkB;IAC5B,WAAW,EAAE,WAAW;IACxB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,EAAE,KAAM;IACvB;;;;;OAKG;IACH,oBAAoB,EAAE,wBAAwB;IAC9C;;;;;;;;;;OAUG;IACH,WAAW,EAAE;QACX,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAEF,IAAI,yBAAyB,IAAI,eAAe,EAAE,CAAC;IACjD,OAAO,CAAC,GAAG,GAAG;QACZ,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,IACE,yBAAyB;IACzB,eAAe;IACf,iBAAiB;IACjB,gBAAgB,EAChB,CAAC;IACD,OAAO,CAAC,GAAG,GAAG;QACZ,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;QACrC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAkC,OAAO,CAAC;AAExE,MAAM,CAAC,MAAM,uBAAuB,mCAC/B,OAAO,KACV,oBAAoB,EAAE,8BAA8B,GACrD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,0BAA0B,mCAClC,OAAO,KACV,eAAe,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,GAChC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAChC,iBAAiB,CAAC"}
|
|
@@ -8,7 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import logger from "../Utils/Logger";
|
|
11
|
-
import { dataSourceOptions, ingestDataSourceOptions, testDataSourceOptions, } from "./ClickhouseConfig";
|
|
11
|
+
import { dataSourceOptions, ingestDataSourceOptions, migrationDataSourceOptions, testDataSourceOptions, } from "./ClickhouseConfig";
|
|
12
12
|
import { createClient } from "@clickhouse/client";
|
|
13
13
|
import DatabaseNotConnectedException from "../../Types/Exception/DatabaseNotConnectedException";
|
|
14
14
|
import Sleep from "../../Types/Sleep";
|
|
@@ -150,4 +150,13 @@ export const ClickhouseAppInstance = new ClickhouseDatabase(dataSourceOptions);
|
|
|
150
150
|
* sockets when ingest is bursting.
|
|
151
151
|
*/
|
|
152
152
|
export const ClickhouseIngestInstance = new ClickhouseDatabase(ingestDataSourceOptions);
|
|
153
|
+
/*
|
|
154
|
+
* Separate pool for schema sync + data migrations. Identical to the App pool
|
|
155
|
+
* except for a much higher request_timeout (see migrationDataSourceOptions):
|
|
156
|
+
* the App pool's 58s socket-idle timer is correct for dashboard reads but
|
|
157
|
+
* would destroy a long-running migration DDL/mutation mid-flight and crash
|
|
158
|
+
* boot. Schema sync and migrations route through this instance via
|
|
159
|
+
* MigrationExecuteOptions (AnalyticsDatabaseService).
|
|
160
|
+
*/
|
|
161
|
+
export const ClickhouseMigrationInstance = new ClickhouseDatabase(migrationDataSourceOptions);
|
|
153
162
|
//# sourceMappingURL=ClickhouseDatabase.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClickhouseDatabase.js","sourceRoot":"","sources":["../../../../Server/Infrastructure/ClickhouseDatabase.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ClickhouseDatabase.js","sourceRoot":"","sources":["../../../../Server/Infrastructure/ClickhouseDatabase.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { WorkflowHostname } from "../EnvironmentConfig";
|
|
11
|
-
import { ClickhouseAppInstance, ClickhouseIngestInstance, } from "../Infrastructure/ClickhouseDatabase";
|
|
11
|
+
import { ClickhouseAppInstance, ClickhouseIngestInstance, ClickhouseMigrationInstance, } from "../Infrastructure/ClickhouseDatabase";
|
|
12
12
|
import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
|
|
13
13
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
14
|
import ModelPermission from "../Types/AnalyticsDatabase/ModelPermission";
|
|
@@ -40,6 +40,29 @@ import Typeof from "../../Types/Typeof";
|
|
|
40
40
|
import API from "../../Utils/API";
|
|
41
41
|
import AggregationType from "../../Types/BaseDatabase/AggregationType";
|
|
42
42
|
import ModelEventType from "../../Types/Realtime/ModelEventType";
|
|
43
|
+
/**
|
|
44
|
+
* Standard options for every schema-sync / data-migration statement. Two
|
|
45
|
+
* layers of protection against the socket-idle `request_timeout` killing a
|
|
46
|
+
* long migration:
|
|
47
|
+
* 1. `useMigrationConnection` routes through ClickhouseMigrationInstance
|
|
48
|
+
* (30-minute idle ceiling) — reliable even for pure-DDL / ON CLUSTER
|
|
49
|
+
* coordination that streams no bytes at all.
|
|
50
|
+
* 2. `send_progress_in_http_headers` makes the server emit periodic
|
|
51
|
+
* X-ClickHouse-Progress header lines for data-rewriting statements
|
|
52
|
+
* (MODIFY COLUMN rewrites, MATERIALIZE, INSERT...SELECT), keeping the
|
|
53
|
+
* socket non-idle so the request completes instead of timing out.
|
|
54
|
+
* Pass this as the second arg to `execute` / `executeQuery` from migration
|
|
55
|
+
* code. The schema-mutating helpers on this service default to it already.
|
|
56
|
+
*/
|
|
57
|
+
export const MigrationExecuteOptions = {
|
|
58
|
+
useMigrationConnection: true,
|
|
59
|
+
clickhouseSettings: {
|
|
60
|
+
send_progress_in_http_headers: 1,
|
|
61
|
+
// Emit a progress header every 10s — well under the App pool's 58s and the
|
|
62
|
+
// migration pool's 30-minute idle ceiling.
|
|
63
|
+
http_headers_progress_interval_ms: "10000",
|
|
64
|
+
},
|
|
65
|
+
};
|
|
43
66
|
const insertDedupContext = new AsyncLocalStorage();
|
|
44
67
|
export function runWithInsertDedup(tokenBase, fn) {
|
|
45
68
|
return insertDedupContext.run({ tokenBase, chunkIndexByTable: new Map() }, fn);
|
|
@@ -61,8 +84,15 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
61
84
|
else {
|
|
62
85
|
this.ingestDatabase = ClickhouseIngestInstance;
|
|
63
86
|
}
|
|
87
|
+
/*
|
|
88
|
+
* Migrations route through their own pool (higher socket-idle timeout) via
|
|
89
|
+
* MigrationExecuteOptions. In tests `data.database` is the in-test instance,
|
|
90
|
+
* so reuse it there to keep tests on a single mocked client.
|
|
91
|
+
*/
|
|
92
|
+
this.migrationDatabase = data.database || ClickhouseMigrationInstance;
|
|
64
93
|
this.databaseClient = this.database.getDataSource();
|
|
65
94
|
this.ingestDatabaseClient = this.ingestDatabase.getDataSource();
|
|
95
|
+
this.migrationDatabaseClient = this.migrationDatabase.getDataSource();
|
|
66
96
|
this.statementGenerator = new StatementGenerator({
|
|
67
97
|
modelType: this.modelType,
|
|
68
98
|
database: this.database,
|
|
@@ -228,11 +258,14 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
228
258
|
}
|
|
229
259
|
async addColumnInDatabase(column) {
|
|
230
260
|
const statement = this.statementGenerator.toAddColumnStatement(column);
|
|
231
|
-
|
|
261
|
+
// Schema-sync / migration-only path: route through the migration pool so a
|
|
262
|
+
// column add that backfills a DEFAULT/MATERIALIZED expression on a large
|
|
263
|
+
// table is not destroyed at the App pool's 58s socket-idle timeout.
|
|
264
|
+
await this.execute(statement, MigrationExecuteOptions);
|
|
232
265
|
// Add skip index separately (ClickHouse requires ADD INDEX as a separate ALTER statement)
|
|
233
266
|
const indexStatement = this.statementGenerator.toAddSkipIndexStatement(column);
|
|
234
267
|
if (indexStatement) {
|
|
235
|
-
await this.execute(indexStatement);
|
|
268
|
+
await this.execute(indexStatement, MigrationExecuteOptions);
|
|
236
269
|
}
|
|
237
270
|
}
|
|
238
271
|
async dropColumnInDatabase(columnName) {
|
|
@@ -244,9 +277,9 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
244
277
|
return col.key === columnName;
|
|
245
278
|
});
|
|
246
279
|
if (column === null || column === void 0 ? void 0 : column.skipIndex) {
|
|
247
|
-
await this.execute(this.statementGenerator.toDropSkipIndexStatement(column.skipIndex.name));
|
|
280
|
+
await this.execute(this.statementGenerator.toDropSkipIndexStatement(column.skipIndex.name), MigrationExecuteOptions);
|
|
248
281
|
}
|
|
249
|
-
await this.execute(this.statementGenerator.toDropColumnStatement(columnName));
|
|
282
|
+
await this.execute(this.statementGenerator.toDropColumnStatement(columnName), MigrationExecuteOptions);
|
|
250
283
|
}
|
|
251
284
|
async doesColumnExist(columnName) {
|
|
252
285
|
// Columns live on the physical (local) storage table in cluster mode.
|
|
@@ -290,7 +323,7 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
290
323
|
logger.info(`${tableName}.${data.columnName} already has ${data.expectedCodecValue}, skipping`, { tableName });
|
|
291
324
|
return;
|
|
292
325
|
}
|
|
293
|
-
await this.execute(`ALTER TABLE ${tableName} MODIFY COLUMN ${data.columnName} ${data.columnType} CODEC(${data.codec}) SETTINGS mutations_sync=0
|
|
326
|
+
await this.execute(`ALTER TABLE ${tableName} MODIFY COLUMN ${data.columnName} ${data.columnType} CODEC(${data.codec}) SETTINGS mutations_sync=0`, MigrationExecuteOptions);
|
|
294
327
|
logger.info(`Applied ${data.codec} codec to ${tableName}.${data.columnName} (async)`, { tableName });
|
|
295
328
|
}
|
|
296
329
|
async findBy(findBy) {
|
|
@@ -892,9 +925,13 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
892
925
|
this.databaseClient = this.database.getDataSource();
|
|
893
926
|
this.ingestDatabase = ClickhouseIngestInstance;
|
|
894
927
|
this.ingestDatabaseClient = this.ingestDatabase.getDataSource();
|
|
928
|
+
this.migrationDatabase = ClickhouseMigrationInstance;
|
|
929
|
+
this.migrationDatabaseClient = this.migrationDatabase.getDataSource();
|
|
895
930
|
}
|
|
896
931
|
async execute(statement, options) {
|
|
897
|
-
const client =
|
|
932
|
+
const client = (options === null || options === void 0 ? void 0 : options.useMigrationConnection)
|
|
933
|
+
? this.getMigrationClient()
|
|
934
|
+
: this.getDatabaseClient();
|
|
898
935
|
const query = statement instanceof Statement ? statement.query : statement;
|
|
899
936
|
const queryParams = statement instanceof Statement ? statement.query_params : undefined;
|
|
900
937
|
return (await client.exec(Object.assign(Object.assign({ query: query, query_params: queryParams || undefined }, ((options === null || options === void 0 ? void 0 : options.clickhouseSettings)
|
|
@@ -902,7 +939,9 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
902
939
|
: {})), ((options === null || options === void 0 ? void 0 : options.queryId) ? { query_id: options.queryId } : {}))));
|
|
903
940
|
}
|
|
904
941
|
async executeQuery(statement, options) {
|
|
905
|
-
const client =
|
|
942
|
+
const client = (options === null || options === void 0 ? void 0 : options.useMigrationConnection)
|
|
943
|
+
? this.getMigrationClient()
|
|
944
|
+
: this.getDatabaseClient();
|
|
906
945
|
const query = statement instanceof Statement ? statement.query : statement;
|
|
907
946
|
const queryParams = statement instanceof Statement ? statement.query_params : undefined;
|
|
908
947
|
return await client.query(Object.assign(Object.assign({ query: query, format: "JSON", query_params: queryParams || undefined }, ((options === null || options === void 0 ? void 0 : options.clickhouseSettings)
|
|
@@ -937,6 +976,18 @@ export default class AnalyticsDatabaseService extends BaseService {
|
|
|
937
976
|
}
|
|
938
977
|
return this.ingestDatabaseClient;
|
|
939
978
|
}
|
|
979
|
+
getMigrationClient() {
|
|
980
|
+
if (!this.migrationDatabase) {
|
|
981
|
+
this.useDefaultDatabase();
|
|
982
|
+
}
|
|
983
|
+
if (!this.migrationDatabaseClient && this.migrationDatabase) {
|
|
984
|
+
this.migrationDatabaseClient = this.migrationDatabase.getDataSource();
|
|
985
|
+
}
|
|
986
|
+
if (!this.migrationDatabaseClient) {
|
|
987
|
+
throw new Exception(ExceptionCode.DatabaseNotConnectedException, "ClickHouse migration client is not connected");
|
|
988
|
+
}
|
|
989
|
+
return this.migrationDatabaseClient;
|
|
990
|
+
}
|
|
940
991
|
async onUpdateSuccess(onUpdate, _updatedItemIds) {
|
|
941
992
|
// A place holder method used for overriding.
|
|
942
993
|
return Promise.resolve(onUpdate);
|