Skip to content

Lazy-load heavy optional server dependencies (apache-arrow, openpgp, node-jose, pdfmake, langchain entry points) - #300786

Closed
sphilipse wants to merge 1 commit into
elastic:mainfrom
sphilipse:lazy-load-heavy-server-deps
Closed

sphilipse wants to merge 1 commit into
elastic:mainfrom
sphilipse:lazy-load-heavy-server-deps

Conversation

@sphilipse

@sphilipse sphilipse commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

Several large libraries are loaded into server memory at plugin setup even though they are only needed when a specific feature is exercised. An idle-heap inventory (heap snapshot + full multi-parent require.cache graph) showed each of these has a single — or very few — eager import roots, so they can be deferred with contained changes:

Library Modules Eager root Now loaded when
apache-arrow 146 alerting_v2 arrow response format an arrow-format ES|QL query runs
@elastic/request-crypto + node-jose + node-forge 134 telemetry_collection_manager encryption telemetry is sent
openpgp 25 fleet package signature verification a key is read / signature verified
pdfmake + fontkit + brotli ~60 screenshotting main thread (bundle-inclusion import) only in the PDF worker thread
@kbn/inference-langchain (langchain tree) inference chat-model factory a chat model is requested
@kbn/agent-builder-genai-utils (langchain tree) esql NL-to-ES|QL + suggest-fix routes those routes are called

Notes:

  • All conversions sit inside already-async functions. The only signature change is decodeArrowBatch (internal to alerting_v2) receiving the arrow Type.Timestamp id instead of importing the enum at module scope.
  • screenshotting previously executed import './worker_dependencies' on the main thread purely to keep pdfmake in the release bundle; this is now a never-invoked dynamic-import reference, so only the worker thread pays for it. Flagging for the owning team: please confirm the release-bundle scanner picks up dynamic import specifiers (pdfmake is also a root package.json dependency).
  • The two langchain entry points only fully unload the langchain tree once the remaining eager roots (security_solution SIEM migrations, automatic_import, elastic_assistant, agent_builder — 114 importing files in security_solution alone) are also lazy or disabled. They are still worth fixing now so reduced configurations benefit immediately.

Testing

  • node scripts/jest for all touched areas: alerting_v2 formats (22), esql routes (48), telemetry encryption (7), fleet package verification (3), screenshotting pdf (2), inference client (7) — all pass
  • node scripts/type_check --project … for all six touched plugins — pass

🤖 Generated with Claude Code

Production measurements (cumulative)

Idle production source builds (node scripts/build, bin/kibana against a local ES, allocation-tracking preload, 2 min idle, GC-forced heap snapshot + full require graph; same machine and protocol for every row):

Build Modules in require.cache Heap snapshot self size Idle heap_used Δ self size
main (63948de) 31,175 698.4 MB ~629 MB —
+ #300785 (swc fs-cache) no production effect — dev-only tooling 698.4 MB — 0
+ #300786 (lazy heavy deps) 30,885 697.4 MB ~632 MB −1.0 MB
+ #300920 (EUI off the server) 28,932 614.7 MB ~580 MB −82.7 MB
+ #300921 (GenAI stack lazy) 26,992 577.4 MB ~545 MB −37.3 MB
total −4,183 −121.0 MB ≈ −84 MB

Single-run samples; heap_used has ±10 MB run noise, snapshot self size is GC-forced and stabler.

Several large libraries were loaded into server memory at plugin setup even
though they are only needed when a specific feature is exercised. Convert
their single eager import sites to dynamic imports at first use:

- apache-arrow (146 modules): alerting_v2 arrow response format; loaded when
  an arrow-format ES|QL query runs. decodeArrowBatch now receives the
  Timestamp type id instead of importing the enum at module scope.
- openpgp (25 modules): fleet package signature verification; loaded when a
  key is read or a signature verified.
- @elastic/request-crypto + node-jose (134 modules): telemetry encryption;
  loaded when telemetry is sent.
- pdfmake + fontkit + brotli: screenshotting imported worker_dependencies in
  the main thread purely to keep them in the release bundle; replace with a
  never-invoked dynamic-import reference so only the PDF worker thread loads
  them.
- @kbn/inference-langchain: inference plugin chat-model factory; loaded when
  a chat model is requested.
- @kbn/agent-builder-genai-utils: esql NL-to-ES|QL and suggest-fix routes;
  loaded when those routes are called.

The langchain entry points only fully unload the langchain tree when the
remaining eager roots (security_solution SIEM migrations, automatic_import,
elastic_assistant, agent_builder) are also made lazy or disabled; they are
still worth fixing at these chokepoints so minimal configurations benefit.

All conversions sit inside already-async functions; no public API changes
beyond decodeArrowBatch (internal to alerting_v2) gaining a parameter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release_note:skip Skip the PR/issue when compiling release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant