@malloy-publisher/server 0.0.235 → 0.0.236
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/dist/app/api-doc.yaml +47 -17
- package/dist/package_load_worker.mjs +8 -1
- package/dist/server.mjs +471 -54
- package/package.json +5 -2
- package/.eslintrc.json +0 -44
- package/.prettierignore +0 -1
- package/.prettierrc +0 -4
- package/build.ts +0 -97
- package/eslint.config.mjs +0 -76
- package/k6-tests/README.md +0 -144
- package/k6-tests/bun.lock +0 -797
- package/k6-tests/load-test/load-test-crud-connections.ts +0 -263
- package/k6-tests/load-test/load-test-crud-packages.ts +0 -461
- package/k6-tests/load-test/load-test-crud-projects.ts +0 -160
- package/k6-tests/load-test/load-test-crud.ts +0 -142
- package/k6-tests/load-test/load-test.ts +0 -784
- package/k6-tests/package.json +0 -27
- package/k6-tests/scripts/run-with-otel.sh +0 -50
- package/k6-tests/smoke-test/smoke-test.ts +0 -158
- package/k6-tests/tsconfig.json +0 -29
- package/k6-tests/utils/client_factory.ts +0 -128
- package/k6-tests/utils/common.ts +0 -489
- package/k6-tests/utils/logger.ts +0 -62
- package/k6-tests/utils/types.d.ts +0 -35
- package/malloy_mcp.dxt +0 -0
- package/publisher.config.example.bigquery.json +0 -33
- package/publisher.config.example.duckdb.json +0 -23
- package/publisher.config.json +0 -23
- package/scripts/bake-duckdb-extensions.js +0 -110
- package/src/config.spec.ts +0 -1535
- package/src/config.theme.spec.ts +0 -178
- package/src/config.ts +0 -1142
- package/src/constants.ts +0 -105
- package/src/controller/compile.controller.ts +0 -40
- package/src/controller/connection.controller.spec.ts +0 -849
- package/src/controller/connection.controller.ts +0 -901
- package/src/controller/database.controller.ts +0 -24
- package/src/controller/materialization.controller.spec.ts +0 -293
- package/src/controller/materialization.controller.ts +0 -319
- package/src/controller/model.controller.ts +0 -164
- package/src/controller/package.controller.spec.ts +0 -273
- package/src/controller/package.controller.ts +0 -306
- package/src/controller/query.controller.ts +0 -152
- package/src/controller/theme.controller.ts +0 -83
- package/src/controller/watch-mode.controller.ts +0 -243
- package/src/data_styles.ts +0 -71
- package/src/default-publisher.config.json +0 -23
- package/src/ducklake_version.spec.ts +0 -163
- package/src/ducklake_version.ts +0 -153
- package/src/errors.spec.ts +0 -119
- package/src/errors.ts +0 -237
- package/src/filter_deprecation.spec.ts +0 -64
- package/src/filter_deprecation.ts +0 -42
- package/src/health.spec.ts +0 -123
- package/src/health.ts +0 -233
- package/src/heap_check.spec.ts +0 -144
- package/src/heap_check.ts +0 -144
- package/src/instrumentation.ts +0 -214
- package/src/json_utils.spec.ts +0 -51
- package/src/json_utils.ts +0 -33
- package/src/logger.spec.ts +0 -210
- package/src/logger.ts +0 -251
- package/src/malloy_pin_prereqs.spec.ts +0 -25
- package/src/materialization_metrics.spec.ts +0 -169
- package/src/materialization_metrics.ts +0 -346
- package/src/mcp/error_messages.spec.ts +0 -35
- package/src/mcp/error_messages.ts +0 -183
- package/src/mcp/handler_utils.spec.ts +0 -108
- package/src/mcp/handler_utils.ts +0 -251
- package/src/mcp/mcp_constants.ts +0 -6
- package/src/mcp/query_envelope.spec.ts +0 -229
- package/src/mcp/query_envelope.ts +0 -240
- package/src/mcp/server.protocol.spec.ts +0 -250
- package/src/mcp/server.ts +0 -87
- package/src/mcp/skills/build_skills_bundle.spec.ts +0 -51
- package/src/mcp/skills/build_skills_bundle.ts +0 -176
- package/src/mcp/skills/skills_bundle.json +0 -1
- package/src/mcp/skills/skills_bundle.spec.ts +0 -171
- package/src/mcp/tool_response.spec.ts +0 -108
- package/src/mcp/tool_response.ts +0 -138
- package/src/mcp/tools/compile_tool.spec.ts +0 -315
- package/src/mcp/tools/compile_tool.ts +0 -208
- package/src/mcp/tools/docs_search/build_docs_index.ts +0 -132
- package/src/mcp/tools/docs_search/malloy_docs_index.json +0 -1
- package/src/mcp/tools/docs_search_tool.spec.ts +0 -32
- package/src/mcp/tools/docs_search_tool.ts +0 -128
- package/src/mcp/tools/embedding_index.spec.ts +0 -1236
- package/src/mcp/tools/embedding_index.ts +0 -808
- package/src/mcp/tools/execute_query_tool.spec.ts +0 -294
- package/src/mcp/tools/execute_query_tool.ts +0 -316
- package/src/mcp/tools/get_context_eval.ts +0 -275
- package/src/mcp/tools/get_context_tool.spec.ts +0 -592
- package/src/mcp/tools/get_context_tool.ts +0 -585
- package/src/mcp/tools/reload_package_tool.spec.ts +0 -232
- package/src/mcp/tools/reload_package_tool.ts +0 -132
- package/src/mcp_config.spec.ts +0 -919
- package/src/mcp_config.ts +0 -425
- package/src/oom_guards.integration.spec.ts +0 -269
- package/src/package_load/package_load_pool.spec.ts +0 -252
- package/src/package_load/package_load_pool.ts +0 -931
- package/src/package_load/package_load_worker.ts +0 -1034
- package/src/package_load/protocol.ts +0 -364
- package/src/package_load/rpc_wait_accountant.spec.ts +0 -109
- package/src/package_load/rpc_wait_accountant.ts +0 -76
- package/src/package_load_metrics.spec.ts +0 -114
- package/src/package_load_metrics.ts +0 -127
- package/src/path_safety.spec.ts +0 -158
- package/src/path_safety.ts +0 -146
- package/src/pg_helpers.spec.ts +0 -223
- package/src/pg_helpers.ts +0 -52
- package/src/query_cap_metrics.spec.ts +0 -89
- package/src/query_cap_metrics.ts +0 -116
- package/src/query_concurrency.spec.ts +0 -247
- package/src/query_concurrency.ts +0 -237
- package/src/query_metadata_metrics.ts +0 -49
- package/src/query_param_utils.ts +0 -29
- package/src/query_timeout.spec.ts +0 -224
- package/src/query_timeout.ts +0 -179
- package/src/runtime/publisher.js +0 -328
- package/src/server-old.ts +0 -988
- package/src/server.ts +0 -2059
- package/src/service/annotations.spec.ts +0 -118
- package/src/service/annotations.ts +0 -91
- package/src/service/authorize.spec.ts +0 -154
- package/src/service/authorize.ts +0 -498
- package/src/service/authorize_integration.spec.ts +0 -2041
- package/src/service/build_plan.spec.ts +0 -685
- package/src/service/build_plan.ts +0 -797
- package/src/service/compile_authorize.spec.ts +0 -85
- package/src/service/compile_fragment_techniques.spec.ts +0 -156
- package/src/service/connection.spec.ts +0 -2360
- package/src/service/connection.ts +0 -2187
- package/src/service/connection_config.spec.ts +0 -734
- package/src/service/connection_config.ts +0 -899
- package/src/service/connection_federation.spec.ts +0 -184
- package/src/service/connection_fingerprint.spec.ts +0 -102
- package/src/service/connection_service.spec.ts +0 -711
- package/src/service/connection_service.ts +0 -291
- package/src/service/cron_evaluator.spec.ts +0 -79
- package/src/service/cron_evaluator.ts +0 -105
- package/src/service/db_utils.spec.ts +0 -1085
- package/src/service/db_utils.ts +0 -1502
- package/src/service/duckdb_instance_isolation.spec.ts +0 -137
- package/src/service/ducklake_lazy_attach.spec.ts +0 -110
- package/src/service/embedding_provider.spec.ts +0 -329
- package/src/service/embedding_provider.ts +0 -236
- package/src/service/environment.ts +0 -2191
- package/src/service/environment_admission.spec.ts +0 -344
- package/src/service/environment_compile.spec.ts +0 -197
- package/src/service/environment_store.spec.ts +0 -2274
- package/src/service/environment_store.ts +0 -2434
- package/src/service/environment_store_anchoring.spec.ts +0 -107
- package/src/service/environment_store_clone.spec.ts +0 -350
- package/src/service/explore_visibility.spec.ts +0 -434
- package/src/service/exports_probe.spec.ts +0 -107
- package/src/service/extension_fetch_policy.spec.ts +0 -256
- package/src/service/filter.spec.ts +0 -458
- package/src/service/filter.ts +0 -341
- package/src/service/filter_bypass.spec.ts +0 -418
- package/src/service/filter_integration.spec.ts +0 -1004
- package/src/service/freshness.spec.ts +0 -183
- package/src/service/freshness.ts +0 -112
- package/src/service/gcs_s3_utils.ts +0 -427
- package/src/service/given.ts +0 -105
- package/src/service/givens_integration.spec.ts +0 -219
- package/src/service/manifest_loader.spec.ts +0 -189
- package/src/service/manifest_loader.ts +0 -156
- package/src/service/materialization_build_session.spec.ts +0 -435
- package/src/service/materialization_build_session.ts +0 -681
- package/src/service/materialization_config_validation.spec.ts +0 -99
- package/src/service/materialization_config_validation.ts +0 -120
- package/src/service/materialization_eligibility.spec.ts +0 -158
- package/src/service/materialization_eligibility.ts +0 -305
- package/src/service/materialization_schedule_surface.spec.ts +0 -256
- package/src/service/materialization_scheduler.spec.ts +0 -289
- package/src/service/materialization_scheduler.ts +0 -304
- package/src/service/materialization_serve_transform.spec.ts +0 -1003
- package/src/service/materialization_serve_transform.ts +0 -779
- package/src/service/materialization_service.spec.ts +0 -2373
- package/src/service/materialization_service.ts +0 -2342
- package/src/service/materialization_test_fixtures.ts +0 -249
- package/src/service/model.spec.ts +0 -1157
- package/src/service/model.ts +0 -3370
- package/src/service/model_limits.spec.ts +0 -209
- package/src/service/model_limits.ts +0 -131
- package/src/service/model_storage_serve.spec.ts +0 -193
- package/src/service/model_storage_serve_joins.spec.ts +0 -193
- package/src/service/package.spec.ts +0 -612
- package/src/service/package.ts +0 -1799
- package/src/service/package_manifest.spec.ts +0 -230
- package/src/service/package_manifest.ts +0 -241
- package/src/service/package_memory_governor.spec.ts +0 -173
- package/src/service/package_memory_governor.ts +0 -233
- package/src/service/package_quote_bound_tables.spec.ts +0 -171
- package/src/service/package_race.spec.ts +0 -208
- package/src/service/package_reload_safety.spec.ts +0 -193
- package/src/service/package_rollback.spec.ts +0 -190
- package/src/service/package_worker_path.spec.ts +0 -645
- package/src/service/path_injection.spec.ts +0 -39
- package/src/service/persist_annotation_validation.spec.ts +0 -89
- package/src/service/persist_annotation_validation.ts +0 -59
- package/src/service/persistence_policy.spec.ts +0 -374
- package/src/service/proxy.spec.ts +0 -414
- package/src/service/proxy.ts +0 -248
- package/src/service/query_boundary.spec.ts +0 -470
- package/src/service/query_metadata.spec.ts +0 -408
- package/src/service/query_metadata.ts +0 -492
- package/src/service/query_metadata_identity.spec.ts +0 -149
- package/src/service/query_text.spec.ts +0 -79
- package/src/service/query_text.ts +0 -43
- package/src/service/quoting.spec.ts +0 -135
- package/src/service/quoting.ts +0 -78
- package/src/service/resolve_environment.ts +0 -15
- package/src/service/restricted_mode.spec.ts +0 -299
- package/src/service/source_extraction.ts +0 -225
- package/src/service/theme_store.ts +0 -199
- package/src/storage/DatabaseInterface.ts +0 -198
- package/src/storage/StorageManager.ts +0 -113
- package/src/storage/duckdb/ConnectionRepository.ts +0 -143
- package/src/storage/duckdb/DuckDBConnection.ts +0 -123
- package/src/storage/duckdb/DuckDBRepository.ts +0 -208
- package/src/storage/duckdb/EnvironmentRepository.ts +0 -148
- package/src/storage/duckdb/MaterializationRepository.spec.ts +0 -191
- package/src/storage/duckdb/MaterializationRepository.ts +0 -336
- package/src/storage/duckdb/PackageRepository.ts +0 -135
- package/src/storage/duckdb/schema.ts +0 -229
- package/src/stream_helpers.spec.ts +0 -280
- package/src/stream_helpers.ts +0 -162
- package/src/telemetry.ts +0 -20
- package/src/test_helpers/metrics_harness.ts +0 -166
- package/src/theme_key_parity.spec.ts +0 -57
- package/src/utils.ts +0 -29
- package/tests/fixtures/authorize-compile/model.malloy +0 -9
- package/tests/fixtures/authorize-compile/publisher.json +0 -4
- package/tests/fixtures/html-pages-nopublic/model.malloy +0 -1
- package/tests/fixtures/html-pages-nopublic/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/data.csv +0 -3
- package/tests/fixtures/html-pages-test/public/assets/app.css +0 -3
- package/tests/fixtures/html-pages-test/public/barehtml.html +0 -4
- package/tests/fixtures/html-pages-test/public/bodymeta.html +0 -8
- package/tests/fixtures/html-pages-test/public/data.json +0 -1
- package/tests/fixtures/html-pages-test/public/fitcomment.html +0 -11
- package/tests/fixtures/html-pages-test/public/index.html +0 -9
- package/tests/fixtures/html-pages-test/public/nohead.html +0 -8
- package/tests/fixtures/html-pages-test/public/notfit.html +0 -13
- package/tests/fixtures/html-pages-test/public/slides.html +0 -12
- package/tests/fixtures/html-pages-test/public/sub/page2.html +0 -9
- package/tests/fixtures/html-pages-test/public/unterminated.html +0 -10
- package/tests/fixtures/html-pages-test/publisher.json +0 -5
- package/tests/fixtures/html-pages-test/report.malloy +0 -1
- package/tests/fixtures/persist-multi-level/data/orders.csv +0 -5
- package/tests/fixtures/persist-multi-level/multi_level.malloy +0 -18
- package/tests/fixtures/persist-multi-level/publisher.json +0 -5
- package/tests/fixtures/persist-schedule-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-test/persist_schedule_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-test/publisher.json +0 -7
- package/tests/fixtures/persist-schedule-warn-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-schedule-warn-test/persist_warn_test.malloy +0 -11
- package/tests/fixtures/persist-schedule-warn-test/publisher.json +0 -6
- package/tests/fixtures/persist-test/data/orders.csv +0 -5
- package/tests/fixtures/persist-test/persist_test.malloy +0 -11
- package/tests/fixtures/persist-test/publisher.json +0 -5
- package/tests/fixtures/publisher.config.json +0 -15
- package/tests/fixtures/query-givens/data/orders.csv +0 -7
- package/tests/fixtures/query-givens/model.malloy +0 -34
- package/tests/fixtures/query-givens/publisher.json +0 -5
- package/tests/fixtures/xlsx/database.xlsx +0 -0
- package/tests/harness/mcp_test_setup.ts +0 -332
- package/tests/harness/rest_e2e.ts +0 -68
- package/tests/integration/authorize/compile_authorize_http.integration.spec.ts +0 -92
- package/tests/integration/concurrent_package/concurrent_package.integration.spec.ts +0 -280
- package/tests/integration/duckdb_storage/duckdb_storage.integration.spec.ts +0 -138
- package/tests/integration/first_boot/readiness_line.integration.spec.ts +0 -177
- package/tests/integration/html_pages/html_pages.integration.spec.ts +0 -440
- package/tests/integration/legacy_routes/legacy_routes.integration.spec.ts +0 -259
- package/tests/integration/materialization/environment_list.integration.spec.ts +0 -133
- package/tests/integration/materialization/freshness_gate.integration.spec.ts +0 -292
- package/tests/integration/materialization/manifest_binding.integration.spec.ts +0 -430
- package/tests/integration/materialization/materialization_lifecycle.integration.spec.ts +0 -441
- package/tests/integration/materialization/orchestrated_rebind.integration.spec.ts +0 -150
- package/tests/integration/materialization/reference_manifest.integration.spec.ts +0 -251
- package/tests/integration/materialization/schedule_edit.integration.spec.ts +0 -126
- package/tests/integration/materialization/scheduler.integration.spec.ts +0 -200
- package/tests/integration/materialization/scheduler_recovery.integration.spec.ts +0 -172
- package/tests/integration/materialization/scheduler_transitions.integration.spec.ts +0 -256
- package/tests/integration/materialization/scheduler_wiring.integration.spec.ts +0 -143
- package/tests/integration/mcp/mcp_execute_query_tool.integration.spec.ts +0 -438
- package/tests/integration/mcp/mcp_get_context_semantic.integration.spec.ts +0 -235
- package/tests/integration/mcp/mcp_transport.integration.spec.ts +0 -98
- package/tests/integration/query_givens/query_givens.integration.spec.ts +0 -146
- package/tests/integration/query_givens/query_givens_authorize.integration.spec.ts +0 -121
- package/tests/integration/sdk_givens/sdk_givens.integration.spec.ts +0 -110
- package/tests/integration/watch-mode/watch_mode.integration.spec.ts +0 -421
- package/tests/unit/controller/theme.controller.spec.ts +0 -141
- package/tests/unit/duckdb/attached_databases.test.ts +0 -1243
- package/tests/unit/duckdb/duckdb_connection.test.ts +0 -181
- package/tests/unit/duckdb/legacy_schema_migration.test.ts +0 -197
- package/tests/unit/duckdb/repositories.test.ts +0 -208
- package/tests/unit/ducklake/ducklake.test.ts +0 -952
- package/tests/unit/service/theme_store.spec.ts +0 -139
- package/tsconfig.json +0 -32
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wire protocol between the main thread (`PackageLoadPool`) and a
|
|
3
|
-
* package-load worker thread.
|
|
4
|
-
*
|
|
5
|
-
* Boundary
|
|
6
|
-
* --------
|
|
7
|
-
* The worker performs the **CPU-bound bulk of `Package.create`** off
|
|
8
|
-
* the main event loop:
|
|
9
|
-
*
|
|
10
|
-
* 1. Read `publisher.config.json` (cheap, but already on the worker
|
|
11
|
-
* side of the boundary so the main thread isn't blocked).
|
|
12
|
-
* 2. Compile every `.malloy` / `.malloynb` (the Malloy parser,
|
|
13
|
-
* type-checker, and IR-builder — the dominant CPU cost).
|
|
14
|
-
* 3. Return a structured-clonable POJO carrying every `modelDef`,
|
|
15
|
-
* `sourceInfos`, dataStyles, etc. that the main thread needs to
|
|
16
|
-
* reconstitute a live `Package`.
|
|
17
|
-
*
|
|
18
|
-
* Embedded database probing (`.parquet` / `.csv` schema + row count)
|
|
19
|
-
* stays on the main thread — it reuses the package's existing DuckDB
|
|
20
|
-
* connection and the probe queries are async-IO-bound, not
|
|
21
|
-
* CPU-bound. Keeping all native-DB handles on the main thread also
|
|
22
|
-
* sidesteps Bun crash 0x20131 where duckdb-native cannot be loaded
|
|
23
|
-
* into more than one isolate of the same process.
|
|
24
|
-
*
|
|
25
|
-
* The main thread reconstitutes by:
|
|
26
|
-
* - Building a fresh `MalloyConfig` against its own connection pool
|
|
27
|
-
* (live native handles can't cross the worker boundary).
|
|
28
|
-
* - Lazy-hydrating each model's `ModelMaterializer` from `modelDef`
|
|
29
|
-
* via `Runtime._loadModelFromModelDef` on first query — NO
|
|
30
|
-
* recompile, so the first query never re-runs the compiler on
|
|
31
|
-
* the main thread.
|
|
32
|
-
*
|
|
33
|
-
* Per-model compile failures are returned in-band on
|
|
34
|
-
* `SerializedModel.compilationError` so a single bad model doesn't
|
|
35
|
-
* abort the rest of the package load. The main thread decides
|
|
36
|
-
* whether/when to surface as a fatal `Package.create` error (today
|
|
37
|
-
* it throws on the first error; `Package.reloadAllModels` keeps the
|
|
38
|
-
* failed models as placeholders in the package's model map).
|
|
39
|
-
*
|
|
40
|
-
* Whole-package failures (manifest missing, FS errors, worker
|
|
41
|
-
* crashes) come back as `LoadPackageError`. The pool main-thread
|
|
42
|
-
* half (`PackageLoadPool.loadPackage`) rejects with a deserialised
|
|
43
|
-
* Error; `Package.loadViaWorker` then rewraps any non-compile
|
|
44
|
-
* failure as `ServiceUnavailableError` so the HTTP layer responds
|
|
45
|
-
* 503 (transient, retryable) — there is no in-process fallback.
|
|
46
|
-
*
|
|
47
|
-
* Direction summary
|
|
48
|
-
* -----------------
|
|
49
|
-
* main ──▶ worker: LoadPackageRequest (start)
|
|
50
|
-
* worker ──▶ main: LoadPackageResult (success)
|
|
51
|
-
* worker ──▶ main: LoadPackageError (whole-package failure)
|
|
52
|
-
*
|
|
53
|
-
* worker ──▶ main: ConnectionMetadataRequest (proxy non-duckdb lookups)
|
|
54
|
-
* worker ──▶ main: SchemaForTablesRequest (proxy schema fetch)
|
|
55
|
-
* worker ──▶ main: SchemaForSqlRequest (proxy SQL block schema)
|
|
56
|
-
* worker ──▶ main: ReadUrlRequest (proxy non-file URL reads)
|
|
57
|
-
* main ──▶ worker: *Response (correlated by requestId)
|
|
58
|
-
*
|
|
59
|
-
* main ──▶ worker: ShutdownRequest (graceful drain)
|
|
60
|
-
* worker ──▶ main: ReadyMessage (post-init handshake)
|
|
61
|
-
*
|
|
62
|
-
* The protocol uses plain structured-clonable POJOs so the
|
|
63
|
-
* `postMessage` transfer goes through V8's structured clone — much
|
|
64
|
-
* cheaper than `JSON.stringify` for the multi-MB modelDef payloads.
|
|
65
|
-
*/
|
|
66
|
-
|
|
67
|
-
import type { SQLSourceDef, TableSourceDef } from "@malloydata/malloy";
|
|
68
|
-
import type {
|
|
69
|
-
PackageMaterializationConfig,
|
|
70
|
-
PackageScope,
|
|
71
|
-
} from "../service/package_manifest";
|
|
72
|
-
|
|
73
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
74
|
-
// Direction: main ──▶ worker (load-package job)
|
|
75
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Connection metadata the worker needs to construct a stub
|
|
79
|
-
* `InfoConnection`. Resolved lazily — the worker asks the main thread
|
|
80
|
-
* on the first `lookupConnection(name)` call (see
|
|
81
|
-
* {@link ConnectionMetadataRequest}). We don't ship the full list
|
|
82
|
-
* upfront because Malloy only references connections by name as it
|
|
83
|
-
* encounters `<connection>.table('...')` / `<connection>.sql('...')`
|
|
84
|
-
* inside the model.
|
|
85
|
-
*/
|
|
86
|
-
export interface ConnectionMetadata {
|
|
87
|
-
name: string;
|
|
88
|
-
dialectName: string;
|
|
89
|
-
digest: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface LoadPackageRequest {
|
|
93
|
-
type: "load-package";
|
|
94
|
-
requestId: string;
|
|
95
|
-
/** Absolute path to the package directory on disk. */
|
|
96
|
-
packagePath: string;
|
|
97
|
-
/** Logical package name (used in metric labels + log fields). */
|
|
98
|
-
packageName: string;
|
|
99
|
-
/**
|
|
100
|
-
* Default connection name (passed verbatim to the worker; today
|
|
101
|
-
* always `"duckdb"` for embedded packages, but kept configurable
|
|
102
|
-
* to mirror Malloy's own surface).
|
|
103
|
-
*/
|
|
104
|
-
defaultConnectionName: string | null;
|
|
105
|
-
/** Optional row-build manifest passed through to Malloy Runtime. */
|
|
106
|
-
buildManifest?: unknown;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
110
|
-
// Direction: worker ──▶ main (load-package result)
|
|
111
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Wire shape for one compiled model in the package. Mirrors the
|
|
115
|
-
* data a main-thread `Model` constructor needs without holding a
|
|
116
|
-
* `ModelMaterializer` reference (that binds to live native
|
|
117
|
-
* connection handles and can't cross the worker boundary).
|
|
118
|
-
*
|
|
119
|
-
* `compilationError` is set when this single model failed to
|
|
120
|
-
* compile but the rest of the package is fine; the main thread
|
|
121
|
-
* decides whether to abort `Package.create`.
|
|
122
|
-
*/
|
|
123
|
-
export interface SerializedModel {
|
|
124
|
-
/** Path relative to the package root, forward-slash normalized. */
|
|
125
|
-
modelPath: string;
|
|
126
|
-
modelType: "model" | "notebook";
|
|
127
|
-
/** Set when the model compiled successfully. Wire-typed as
|
|
128
|
-
* `unknown` so the protocol module doesn't drag in the full
|
|
129
|
-
* Malloy type surface; cast to `ModelDef` on receipt. */
|
|
130
|
-
modelDef?: unknown;
|
|
131
|
-
/**
|
|
132
|
-
* Precomputed `modelDefToModelInfo(modelDef)`. Shipped from the
|
|
133
|
-
* worker so the main-thread `Model` constructor doesn't pay the
|
|
134
|
-
* derivation cost on every package load and every subsequent
|
|
135
|
-
* `getModel()` / `getNotebook()` API hit can stringify a cached
|
|
136
|
-
* object instead of recomputing.
|
|
137
|
-
*/
|
|
138
|
-
modelInfo?: unknown;
|
|
139
|
-
sourceInfos?: unknown[];
|
|
140
|
-
sources?: unknown[];
|
|
141
|
-
queries?: unknown[];
|
|
142
|
-
filterMap?: Array<[string, unknown[]]>;
|
|
143
|
-
givens?: unknown[];
|
|
144
|
-
/** Notebook (.malloynb) only — per-cell pre-extracted info. */
|
|
145
|
-
notebookCells?: SerializedNotebookCell[];
|
|
146
|
-
/** Accumulated dataStyles from sibling `.styles.json` files. */
|
|
147
|
-
dataStyles?: unknown;
|
|
148
|
-
/** Wall-clock ms spent compiling this single model in the worker. */
|
|
149
|
-
compileDurationMs?: number;
|
|
150
|
-
/** Set when the model failed to compile. */
|
|
151
|
-
compilationError?: SerializedError;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export interface SerializedNotebookCell {
|
|
155
|
-
type: "code" | "markdown";
|
|
156
|
-
/** Raw cell text. */
|
|
157
|
-
text: string;
|
|
158
|
-
/**
|
|
159
|
-
* Per-cell ModelDef captured at the cell's point in the
|
|
160
|
-
* `extendModel` chain. The main thread hydrates a per-cell
|
|
161
|
-
* `ModelMaterializer` from this via
|
|
162
|
-
* `Runtime._loadModelFromModelDef`, so cell-level filter
|
|
163
|
-
* refinement can compile new queries against the correct scope
|
|
164
|
-
* without ever recompiling the .malloynb itself.
|
|
165
|
-
*/
|
|
166
|
-
cellModelDef?: unknown;
|
|
167
|
-
/**
|
|
168
|
-
* The final-query QueryDef for this cell, captured during the
|
|
169
|
-
* worker's compile. Main thread hydrates a `QueryMaterializer`
|
|
170
|
-
* via `ModelMaterializer._loadQueryFromQueryDef` — no recompile.
|
|
171
|
-
*/
|
|
172
|
-
cellQueryDef?: unknown;
|
|
173
|
-
newSources?: unknown[];
|
|
174
|
-
queryInfo?: unknown;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export interface LoadPackageResult {
|
|
178
|
-
type: "load-package-result";
|
|
179
|
-
requestId: string;
|
|
180
|
-
packageMetadata: {
|
|
181
|
-
name?: string;
|
|
182
|
-
description?: string;
|
|
183
|
-
explores?: string[];
|
|
184
|
-
queryableSources?: "declared" | "all";
|
|
185
|
-
manifestLocation?: string | null;
|
|
186
|
-
materialization?: PackageMaterializationConfig | null;
|
|
187
|
-
scope?: PackageScope;
|
|
188
|
-
/**
|
|
189
|
-
* Manifest-shape deprecations the load tolerated (e.g. a root-level
|
|
190
|
-
* `scope`). Surfaced with the package's other policy warnings so a
|
|
191
|
-
* still-parsing-but-outdated manifest is visible without failing a load.
|
|
192
|
-
*/
|
|
193
|
-
manifestWarnings?: string[];
|
|
194
|
-
};
|
|
195
|
-
models: SerializedModel[];
|
|
196
|
-
/** Wall-clock ms inside the worker for the full package load. */
|
|
197
|
-
loadDurationMs: number;
|
|
198
|
-
/**
|
|
199
|
-
* Per-load timing breakdown (subset of {@link loadDurationMs}; the
|
|
200
|
-
* remainder is worker setup + post-compile extraction). See
|
|
201
|
-
* `rpc_wait_accountant.ts` for how compile time is separated from I/O.
|
|
202
|
-
*/
|
|
203
|
-
timings: {
|
|
204
|
-
/**
|
|
205
|
-
* Compile-region wall-clock minus time awaiting proxied schema fetches —
|
|
206
|
-
* a conservative ceiling on Malloy compile CPU.
|
|
207
|
-
*/
|
|
208
|
-
compileDurationMs: number;
|
|
209
|
-
/** Wall-clock awaiting proxied connection schema fetches (union). */
|
|
210
|
-
schemaFetchDurationMs: number;
|
|
211
|
-
/** Number of proxied connection schema fetches the load drove. */
|
|
212
|
-
schemaFetchCount: number;
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export interface LoadPackageError {
|
|
217
|
-
type: "load-package-error";
|
|
218
|
-
requestId: string;
|
|
219
|
-
error: SerializedError;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Error wire-shape. We cannot transfer `Error` instances directly
|
|
224
|
-
* across `postMessage` cleanly (Bun/Node behaviour diverges on stack
|
|
225
|
-
* propagation), so we ship a structured payload and reconstitute on
|
|
226
|
-
* the main thread.
|
|
227
|
-
*/
|
|
228
|
-
export interface SerializedError {
|
|
229
|
-
name: string;
|
|
230
|
-
message: string;
|
|
231
|
-
stack?: string;
|
|
232
|
-
/** Set when the error originated as a Malloy `MalloyError`. */
|
|
233
|
-
malloyProblems?: unknown[];
|
|
234
|
-
/** Set when the error originated as `ModelCompilationError`. */
|
|
235
|
-
isCompilationError?: boolean;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
239
|
-
// Direction: worker ──▶ main (proxy connection metadata)
|
|
240
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
241
|
-
|
|
242
|
-
export interface ConnectionMetadataRequest {
|
|
243
|
-
type: "connection-metadata";
|
|
244
|
-
requestId: string;
|
|
245
|
-
jobId: string;
|
|
246
|
-
connectionName: string;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export interface ConnectionMetadataResponse {
|
|
250
|
-
type: "connection-metadata-response";
|
|
251
|
-
requestId: string;
|
|
252
|
-
ok: true;
|
|
253
|
-
metadata: ConnectionMetadata;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
257
|
-
// Direction: worker ──▶ main (proxy schema fetches for non-duckdb)
|
|
258
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
259
|
-
|
|
260
|
-
export interface SchemaForTablesRequest {
|
|
261
|
-
type: "schema-for-tables";
|
|
262
|
-
requestId: string;
|
|
263
|
-
/** Job this RPC belongs to (so main routes to the right config). */
|
|
264
|
-
jobId: string;
|
|
265
|
-
connectionName: string;
|
|
266
|
-
tables: Record<string, string>;
|
|
267
|
-
options: {
|
|
268
|
-
refreshTimestamp?: number;
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export interface SchemaForTablesResponse {
|
|
273
|
-
type: "schema-for-tables-response";
|
|
274
|
-
requestId: string;
|
|
275
|
-
ok: true;
|
|
276
|
-
schemas: Record<string, TableSourceDef>;
|
|
277
|
-
errors: Record<string, string>;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export interface SchemaForSqlRequest {
|
|
281
|
-
type: "schema-for-sql";
|
|
282
|
-
requestId: string;
|
|
283
|
-
jobId: string;
|
|
284
|
-
connectionName: string;
|
|
285
|
-
sentence: unknown;
|
|
286
|
-
options: {
|
|
287
|
-
refreshTimestamp?: number;
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export interface SchemaForSqlResponse {
|
|
292
|
-
type: "schema-for-sql-response";
|
|
293
|
-
requestId: string;
|
|
294
|
-
ok: true;
|
|
295
|
-
structDef?: SQLSourceDef;
|
|
296
|
-
error?: string;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export interface RpcErrorResponse {
|
|
300
|
-
type: "rpc-error";
|
|
301
|
-
requestId: string;
|
|
302
|
-
ok: false;
|
|
303
|
-
error: SerializedError;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
307
|
-
// Direction: worker ──▶ main (file read for non-file URLs)
|
|
308
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Workers read most files directly via `fs` (they share the host's
|
|
312
|
-
* filesystem namespace). This RPC exists for the rare case where the
|
|
313
|
-
* package URL reader has host-specific behaviour (e.g. virtual files,
|
|
314
|
-
* remote URLs) — we delegate back to the main thread's URL reader so
|
|
315
|
-
* compile semantics stay identical to the in-process path.
|
|
316
|
-
*/
|
|
317
|
-
export interface ReadUrlRequest {
|
|
318
|
-
type: "read-url";
|
|
319
|
-
requestId: string;
|
|
320
|
-
jobId: string;
|
|
321
|
-
url: string;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export interface ReadUrlResponse {
|
|
325
|
-
type: "read-url-response";
|
|
326
|
-
requestId: string;
|
|
327
|
-
ok: true;
|
|
328
|
-
contents: string;
|
|
329
|
-
invalidationKey?: string | number | null;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
333
|
-
// Lifecycle
|
|
334
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
335
|
-
|
|
336
|
-
export interface ShutdownRequest {
|
|
337
|
-
type: "shutdown";
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export interface ReadyMessage {
|
|
341
|
-
type: "ready";
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
345
|
-
// Union types for routing
|
|
346
|
-
// ──────────────────────────────────────────────────────────────────────
|
|
347
|
-
|
|
348
|
-
export type MainToWorkerMessage =
|
|
349
|
-
| LoadPackageRequest
|
|
350
|
-
| ConnectionMetadataResponse
|
|
351
|
-
| SchemaForTablesResponse
|
|
352
|
-
| SchemaForSqlResponse
|
|
353
|
-
| ReadUrlResponse
|
|
354
|
-
| RpcErrorResponse
|
|
355
|
-
| ShutdownRequest;
|
|
356
|
-
|
|
357
|
-
export type WorkerToMainMessage =
|
|
358
|
-
| LoadPackageResult
|
|
359
|
-
| LoadPackageError
|
|
360
|
-
| ConnectionMetadataRequest
|
|
361
|
-
| SchemaForTablesRequest
|
|
362
|
-
| SchemaForSqlRequest
|
|
363
|
-
| ReadUrlRequest
|
|
364
|
-
| ReadyMessage;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import { RpcWaitAccountant } from "./rpc_wait_accountant";
|
|
4
|
-
|
|
5
|
-
/** Accountant driven by a settable fake clock. */
|
|
6
|
-
function withClock(): { acc: RpcWaitAccountant; at: (ms: number) => void } {
|
|
7
|
-
let t = 0;
|
|
8
|
-
const acc = new RpcWaitAccountant(() => t);
|
|
9
|
-
return { acc, at: (ms) => (t = ms) };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
describe("RpcWaitAccountant", () => {
|
|
13
|
-
it("brackets a single fetch's wait", () => {
|
|
14
|
-
const { acc, at } = withClock();
|
|
15
|
-
at(0);
|
|
16
|
-
acc.begin("A");
|
|
17
|
-
at(10);
|
|
18
|
-
acc.noteStart("A");
|
|
19
|
-
at(60);
|
|
20
|
-
acc.noteSettle("A");
|
|
21
|
-
expect(acc.waitMs).toBe(50);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("counts overlapping fetches as their union, not the sum", () => {
|
|
25
|
-
const { acc, at } = withClock();
|
|
26
|
-
at(0);
|
|
27
|
-
acc.begin("A");
|
|
28
|
-
at(0);
|
|
29
|
-
acc.noteStart("A"); // window opens
|
|
30
|
-
at(10);
|
|
31
|
-
acc.noteStart("A"); // second fetch, window stays open
|
|
32
|
-
at(40);
|
|
33
|
-
acc.noteSettle("A"); // one still outstanding
|
|
34
|
-
at(60);
|
|
35
|
-
acc.noteSettle("A"); // window closes
|
|
36
|
-
expect(acc.waitMs).toBe(60); // union [0,60], not 30+50
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("accumulates disjoint fetch windows", () => {
|
|
40
|
-
const { acc, at } = withClock();
|
|
41
|
-
at(0);
|
|
42
|
-
acc.begin("A");
|
|
43
|
-
at(0);
|
|
44
|
-
acc.noteStart("A");
|
|
45
|
-
at(20);
|
|
46
|
-
acc.noteSettle("A");
|
|
47
|
-
at(50);
|
|
48
|
-
acc.noteStart("A");
|
|
49
|
-
at(70);
|
|
50
|
-
acc.noteSettle("A");
|
|
51
|
-
expect(acc.waitMs).toBe(40);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("ignores a straggler fetch from a prior reused-worker load", () => {
|
|
55
|
-
const { acc, at } = withClock();
|
|
56
|
-
at(0);
|
|
57
|
-
acc.begin("A");
|
|
58
|
-
at(0);
|
|
59
|
-
acc.noteStart("A"); // load A opens a fetch and never settles it (failed)
|
|
60
|
-
|
|
61
|
-
at(100);
|
|
62
|
-
acc.begin("B"); // worker reused for load B
|
|
63
|
-
at(110);
|
|
64
|
-
acc.noteStart("B");
|
|
65
|
-
at(130);
|
|
66
|
-
acc.noteSettle("B");
|
|
67
|
-
|
|
68
|
-
at(140);
|
|
69
|
-
acc.noteSettle("A"); // A's late response — must be a no-op
|
|
70
|
-
|
|
71
|
-
expect(acc.waitMs).toBe(20); // only B's [110,130]
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("ignores a stray start from a non-active load", () => {
|
|
75
|
-
const { acc, at } = withClock();
|
|
76
|
-
at(0);
|
|
77
|
-
acc.begin("B");
|
|
78
|
-
at(10);
|
|
79
|
-
acc.noteStart("A"); // wrong load
|
|
80
|
-
at(50);
|
|
81
|
-
acc.noteSettle("A");
|
|
82
|
-
expect(acc.waitMs).toBe(0);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("counts active-load fetches only", () => {
|
|
86
|
-
const { acc, at } = withClock();
|
|
87
|
-
at(0);
|
|
88
|
-
acc.begin("B");
|
|
89
|
-
acc.noteStart("B");
|
|
90
|
-
acc.noteSettle("B");
|
|
91
|
-
acc.noteStart("B");
|
|
92
|
-
acc.noteStart("A"); // straggler — not counted
|
|
93
|
-
expect(acc.fetches).toBe(2);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("begin() discards prior-load state", () => {
|
|
97
|
-
const { acc, at } = withClock();
|
|
98
|
-
at(0);
|
|
99
|
-
acc.begin("A");
|
|
100
|
-
at(0);
|
|
101
|
-
acc.noteStart("A");
|
|
102
|
-
at(50);
|
|
103
|
-
acc.noteSettle("A");
|
|
104
|
-
expect(acc.waitMs).toBe(50);
|
|
105
|
-
at(60);
|
|
106
|
-
acc.begin("B");
|
|
107
|
-
expect(acc.waitMs).toBe(0);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-load "wait" accounting for the package-load worker.
|
|
3
|
-
*
|
|
4
|
-
* A package load spends its time in two very different ways: CPU-bound Malloy
|
|
5
|
-
* compilation, and I/O waiting on connection schema fetches that are proxied
|
|
6
|
-
* back to the main thread. Today only the *total* load time is observable, so
|
|
7
|
-
* an operator seeing slow loads can't tell which half dominates. This tracks
|
|
8
|
-
* the wall-clock during which at least one proxied schema fetch is outstanding,
|
|
9
|
-
* so the load handler can report `compile = compileRegion - schemaFetchWait`
|
|
10
|
-
* alongside the fetch time itself.
|
|
11
|
-
*
|
|
12
|
-
* Why wall-minus-wait and not a CPU counter: worker threads share the host
|
|
13
|
-
* process, so `process.cpuUsage()` is process-wide and would fold in every
|
|
14
|
-
* other worker's CPU — useless for a per-load number. Wall-minus-wait is the
|
|
15
|
-
* honest per-load proxy. Treat the compute figure as a conservative *ceiling*
|
|
16
|
-
* on compile CPU: only proxied waits are subtracted, so any non-fetch stall
|
|
17
|
-
* (GC, scheduler preemption) also lands in "compute".
|
|
18
|
-
*
|
|
19
|
-
* Overlapping fetches are counted as their union (the wall-time with >=1
|
|
20
|
-
* outstanding), never the sum, so concurrent fetches during one compile don't
|
|
21
|
-
* over-subtract.
|
|
22
|
-
*
|
|
23
|
-
* Scoped by `jobId`: the pool runs one load per worker at a time, but reuses a
|
|
24
|
-
* worker across loads, and a load that fails can leave a proxied fetch in
|
|
25
|
-
* flight. Gating every start/settle on the active job makes such a straggler's
|
|
26
|
-
* late response a no-op instead of corrupting the next load's numbers. (If the
|
|
27
|
-
* one-load-per-worker rule ever changes, this stays correct per job but the
|
|
28
|
-
* compute ceiling would then also fold in a sibling load's CPU.)
|
|
29
|
-
*/
|
|
30
|
-
export class RpcWaitAccountant {
|
|
31
|
-
private inFlight = 0;
|
|
32
|
-
private waitStartMs = 0;
|
|
33
|
-
private accumMs = 0;
|
|
34
|
-
private startedCount = 0;
|
|
35
|
-
private activeJobId: string | undefined;
|
|
36
|
-
|
|
37
|
-
constructor(private readonly now: () => number = () => performance.now()) {}
|
|
38
|
-
|
|
39
|
-
/** Begin accounting for `jobId`, discarding any prior-load state. */
|
|
40
|
-
begin(jobId: string): void {
|
|
41
|
-
this.activeJobId = jobId;
|
|
42
|
-
this.inFlight = 0;
|
|
43
|
-
this.waitStartMs = 0;
|
|
44
|
-
this.accumMs = 0;
|
|
45
|
-
this.startedCount = 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** A proxied fetch for `jobId` was issued. Ignored if `jobId` isn't active. */
|
|
49
|
-
noteStart(jobId: string): void {
|
|
50
|
-
if (jobId !== this.activeJobId) return;
|
|
51
|
-
if (this.inFlight === 0) this.waitStartMs = this.now();
|
|
52
|
-
this.inFlight += 1;
|
|
53
|
-
this.startedCount += 1;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* A proxied fetch for `jobId` settled (resolved or rejected). Ignored if
|
|
58
|
-
* `jobId` isn't active, so a straggler from a prior reused-worker load
|
|
59
|
-
* can't drive the counter negative or close the active load's bracket.
|
|
60
|
-
*/
|
|
61
|
-
noteSettle(jobId: string): void {
|
|
62
|
-
if (jobId !== this.activeJobId) return;
|
|
63
|
-
this.inFlight -= 1;
|
|
64
|
-
if (this.inFlight === 0) this.accumMs += this.now() - this.waitStartMs;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** Accumulated wall-time with >=1 active-load fetch outstanding (union). */
|
|
68
|
-
get waitMs(): number {
|
|
69
|
-
return this.accumMs;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Number of proxied fetches started for the active load. */
|
|
73
|
-
get fetches(): number {
|
|
74
|
-
return this.startedCount;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
recordPackageLoadPhases,
|
|
5
|
-
resetPackageLoadMetricsForTesting,
|
|
6
|
-
} from "./package_load_metrics";
|
|
7
|
-
import {
|
|
8
|
-
startMetricsHarness,
|
|
9
|
-
type MetricsHarness,
|
|
10
|
-
} from "./test_helpers/metrics_harness";
|
|
11
|
-
|
|
12
|
-
describe("package_load_metrics", () => {
|
|
13
|
-
let harness: MetricsHarness;
|
|
14
|
-
|
|
15
|
-
beforeEach(async () => {
|
|
16
|
-
harness = await startMetricsHarness();
|
|
17
|
-
resetPackageLoadMetricsForTesting();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(async () => {
|
|
21
|
-
resetPackageLoadMetricsForTesting();
|
|
22
|
-
await harness.shutdown();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("records the three phase histograms, labeled by status", async () => {
|
|
26
|
-
recordPackageLoadPhases(
|
|
27
|
-
{
|
|
28
|
-
compileDurationMs: 120,
|
|
29
|
-
schemaFetchDurationMs: 80,
|
|
30
|
-
schemaFetchCount: 4,
|
|
31
|
-
},
|
|
32
|
-
"success",
|
|
33
|
-
);
|
|
34
|
-
recordPackageLoadPhases(
|
|
35
|
-
{
|
|
36
|
-
compileDurationMs: 40,
|
|
37
|
-
schemaFetchDurationMs: 10,
|
|
38
|
-
schemaFetchCount: 1,
|
|
39
|
-
},
|
|
40
|
-
"success",
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const compile = await harness.collectHistogram(
|
|
44
|
-
"malloy_package_load_compile_duration",
|
|
45
|
-
{ status: "success" },
|
|
46
|
-
);
|
|
47
|
-
expect(compile.count).toBe(2);
|
|
48
|
-
expect(compile.sum).toBe(160);
|
|
49
|
-
|
|
50
|
-
const fetchDuration = await harness.collectHistogram(
|
|
51
|
-
"malloy_package_load_schema_fetch_duration",
|
|
52
|
-
{ status: "success" },
|
|
53
|
-
);
|
|
54
|
-
expect(fetchDuration.count).toBe(2);
|
|
55
|
-
expect(fetchDuration.sum).toBe(90);
|
|
56
|
-
|
|
57
|
-
const fetches = await harness.collectHistogram(
|
|
58
|
-
"malloy_package_load_schema_fetches",
|
|
59
|
-
{ status: "success" },
|
|
60
|
-
);
|
|
61
|
-
expect(fetches.count).toBe(2);
|
|
62
|
-
expect(fetches.sum).toBe(5);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("labels phases by terminal status, so failures are separable from successes", async () => {
|
|
66
|
-
recordPackageLoadPhases(
|
|
67
|
-
{
|
|
68
|
-
compileDurationMs: 30,
|
|
69
|
-
schemaFetchDurationMs: 5,
|
|
70
|
-
schemaFetchCount: 1,
|
|
71
|
-
},
|
|
72
|
-
"success",
|
|
73
|
-
);
|
|
74
|
-
recordPackageLoadPhases(
|
|
75
|
-
{
|
|
76
|
-
compileDurationMs: 12,
|
|
77
|
-
schemaFetchDurationMs: 3,
|
|
78
|
-
schemaFetchCount: 1,
|
|
79
|
-
},
|
|
80
|
-
"compilation_error",
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
const ok = await harness.collectHistogram(
|
|
84
|
-
"malloy_package_load_compile_duration",
|
|
85
|
-
{ status: "success" },
|
|
86
|
-
);
|
|
87
|
-
const failed = await harness.collectHistogram(
|
|
88
|
-
"malloy_package_load_compile_duration",
|
|
89
|
-
{ status: "compilation_error" },
|
|
90
|
-
);
|
|
91
|
-
expect(ok.count).toBe(1);
|
|
92
|
-
expect(ok.sum).toBe(30);
|
|
93
|
-
expect(failed.count).toBe(1);
|
|
94
|
-
expect(failed.sum).toBe(12);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("resolves the slow-load tail past OTel's default 10s cap", async () => {
|
|
98
|
-
// A 90s load would fall in the +Inf bucket under OTel's default
|
|
99
|
-
// boundaries (top = 10000ms); the explicit buckets must extend further.
|
|
100
|
-
recordPackageLoadPhases(
|
|
101
|
-
{
|
|
102
|
-
compileDurationMs: 90_000,
|
|
103
|
-
schemaFetchDurationMs: 0,
|
|
104
|
-
schemaFetchCount: 0,
|
|
105
|
-
},
|
|
106
|
-
"success",
|
|
107
|
-
);
|
|
108
|
-
const compile = await harness.collectHistogram(
|
|
109
|
-
"malloy_package_load_compile_duration",
|
|
110
|
-
);
|
|
111
|
-
expect(compile.boundaries.some((b) => b > 10_000)).toBe(true);
|
|
112
|
-
expect(compile.boundaries[compile.boundaries.length - 1]).toBe(300_000);
|
|
113
|
-
});
|
|
114
|
-
});
|