|
1 | | -import { ClickHouse } from "@internal/clickhouse"; |
| 1 | +import { ClickHouse, type ClickHouseSettings } from "@internal/clickhouse"; |
2 | 2 | import { createHash } from "crypto"; |
3 | 3 | import { ClickhouseEventRepository } from "~/v3/eventRepository/clickhouseEventRepository.server"; |
4 | 4 | import { env } from "~/env.server"; |
@@ -292,6 +292,40 @@ function initializeRealtimeClickhouseClient(): ClickHouse { |
292 | 292 | }); |
293 | 293 | } |
294 | 294 |
|
| 295 | +/** |
| 296 | + * Server-side query protection for the runs-list read pool. Safe as client-level settings ONLY |
| 297 | + * because this pool is read-only (no inserts); a client-level `max_execution_time` on a mixed |
| 298 | + * read+write pool would also kill slow inserts. `readonly=2` enforces read-only while still |
| 299 | + * allowing these settings to apply (`readonly=1` rejects them). `max_concurrent_queries_for_user` |
| 300 | + * is a per-ClickHouse-user (`default`) fail-fast circuit breaker, not per-tenant isolation. |
| 301 | + */ |
| 302 | +function getRunsListClickhouseSettings(): ClickHouseSettings { |
| 303 | + const settings: ClickHouseSettings = { |
| 304 | + max_execution_time: env.RUNS_LIST_CLICKHOUSE_MAX_EXECUTION_TIME, |
| 305 | + timeout_before_checking_execution_speed: 0, |
| 306 | + }; |
| 307 | + |
| 308 | + if (env.RUNS_LIST_CLICKHOUSE_READONLY !== "0") { |
| 309 | + settings.readonly = env.RUNS_LIST_CLICKHOUSE_READONLY; |
| 310 | + } |
| 311 | + if (env.RUNS_LIST_CLICKHOUSE_MAX_THREADS !== undefined) { |
| 312 | + settings.max_threads = env.RUNS_LIST_CLICKHOUSE_MAX_THREADS; |
| 313 | + } |
| 314 | + if (env.RUNS_LIST_CLICKHOUSE_MAX_MEMORY_USAGE !== undefined) { |
| 315 | + settings.max_memory_usage = env.RUNS_LIST_CLICKHOUSE_MAX_MEMORY_USAGE.toString(); |
| 316 | + } |
| 317 | + if (env.RUNS_LIST_CLICKHOUSE_MAX_MEMORY_USAGE_FOR_USER !== undefined) { |
| 318 | + settings.max_memory_usage_for_user = |
| 319 | + env.RUNS_LIST_CLICKHOUSE_MAX_MEMORY_USAGE_FOR_USER.toString(); |
| 320 | + } |
| 321 | + if (env.RUNS_LIST_CLICKHOUSE_MAX_CONCURRENT_QUERIES_FOR_USER !== undefined) { |
| 322 | + settings.max_concurrent_queries_for_user = |
| 323 | + env.RUNS_LIST_CLICKHOUSE_MAX_CONCURRENT_QUERIES_FOR_USER; |
| 324 | + } |
| 325 | + |
| 326 | + return settings; |
| 327 | +} |
| 328 | + |
295 | 329 | /** Runs list reads — dashboard + API (`RUNS_LIST_CLICKHOUSE_URL`); |
296 | 330 | * falls back to the default client if unset. */ |
297 | 331 | const defaultRunsListClickhouseClient = singleton( |
@@ -319,6 +353,8 @@ function initializeRunsListClickhouseClient(): ClickHouse { |
319 | 353 | request: env.RUNS_LIST_CLICKHOUSE_COMPRESSION_REQUEST === "1", |
320 | 354 | }, |
321 | 355 | maxOpenConnections: env.RUNS_LIST_CLICKHOUSE_MAX_OPEN_CONNECTIONS, |
| 356 | + requestTimeoutMs: env.RUNS_LIST_CLICKHOUSE_REQUEST_TIMEOUT_MS, |
| 357 | + clickhouseSettings: getRunsListClickhouseSettings(), |
322 | 358 | }); |
323 | 359 | } |
324 | 360 |
|
@@ -550,10 +586,25 @@ function buildOrgClickhouseClient(url: string, clientType: ClientType): ClickHou |
550 | 586 | }, |
551 | 587 | maxOpenConnections: env.REALTIME_BACKEND_NATIVE_CLICKHOUSE_MAX_OPEN_CONNECTIONS, |
552 | 588 | }); |
| 589 | + case "runsList": |
| 590 | + return new ClickHouse({ |
| 591 | + url: parsed.toString(), |
| 592 | + name, |
| 593 | + keepAlive: { |
| 594 | + enabled: env.RUNS_LIST_CLICKHOUSE_KEEP_ALIVE_ENABLED === "1", |
| 595 | + idleSocketTtl: env.RUNS_LIST_CLICKHOUSE_KEEP_ALIVE_IDLE_SOCKET_TTL_MS, |
| 596 | + }, |
| 597 | + logLevel: env.RUNS_LIST_CLICKHOUSE_LOG_LEVEL, |
| 598 | + compression: { |
| 599 | + request: env.RUNS_LIST_CLICKHOUSE_COMPRESSION_REQUEST === "1", |
| 600 | + }, |
| 601 | + maxOpenConnections: env.RUNS_LIST_CLICKHOUSE_MAX_OPEN_CONNECTIONS, |
| 602 | + requestTimeoutMs: env.RUNS_LIST_CLICKHOUSE_REQUEST_TIMEOUT_MS, |
| 603 | + clickhouseSettings: getRunsListClickhouseSettings(), |
| 604 | + }); |
553 | 605 | case "standard": |
554 | 606 | case "query": |
555 | 607 | case "admin": |
556 | | - case "runsList": |
557 | 608 | return new ClickHouse({ |
558 | 609 | url: parsed.toString(), |
559 | 610 | name, |
|
0 commit comments