Files
LangBot/plugins/misc/GeneralParsers/SHARED_RUNTIME.md

3.4 KiB

Shared runtime source candidate (SDK >=0.7.4)

This source declares sharedRuntime: shared-runtime-v1 and componentModel: stateless-v1. It is source-reviewed for the multi-tenant contract; it is not certified and makes no claim of live tenant acceptance.

  • Configuration (enable_vision, vision_llm_model_uuid) is read per invocation through self.get_config(). Nothing from tenant config is copied onto the plugin, the Parser component or module globals, so a shared worker is never initialized with another installation's settings.
  • The installation binding is resolved per invocation with self.get_installation_binding() and only used to derive a cache key; the binding object is not retained after the call.

Binding-keyed state

  • Parser telemetry (filenames, MIME types, extensions, durations, parse errors) is tenant data. It is no longer a process-global singleton: TelemetryRegistry keeps one ParserTelemetry per full installation scope (instance_uuid, workspace_uuid, installation_uuid).
  • runtime_revision is deliberately excluded from the scope so a worker upgrade keeps the same bucket.
  • GeneralParsersPlugin.on_installation_revoked(binding) calls release_telemetry(binding), dropping that installation's store on uninstall/disable/workspace-removal/upgrade.

PDF execution boundary

  • PyMuPDF is not thread safe and its table finder keeps module-level page state (EDGES / CHARS in pymupdf.table, unchanged across the supported 1.x line). Parsing it from the shared worker's thread pool let concurrent installations re-enter those globals and could return another installation's page text or crash the shared process.
  • Every PDF parse therefore runs in a dedicated short-lived interpreter process (components/general_parsers/isolated_process.py + process_worker.py) that owns the complete lifecycle: open document -> font/header/footer pass -> find_tables() -> table extraction -> text/image extraction -> close document.
  • The boundary is released only after that process has exited. A hard timeout (DEFAULT_TIMEOUT_SECONDS, 300 s), a cancellation or a crash terminates and reaps the worker before the caller resumes, so no dependency work can keep running into a later request. PyMuPDF module state only ever exists inside the per-parse worker; the shared process never imports it.
  • Supported dependency range: PyMuPDF>=1.24.0,<2.0.0 (see requirements.txt). The process boundary is what makes the shared runtime safe on this whole range; the range is bounded to the 1.x line this implementation is verified against.

Page scoping

PageRequest carries no binding. ParserObservabilityPage resolves the current installation from the task-local SDK binding (self.get_installation_binding()), which the Host sets from the page request's installation context. /snapshot and /clear therefore act only on the calling installation's store and never expose another installation's filenames or errors. When no binding is active (direct, non-invocation use; unit tests) an isolated "unscoped" store is used — it never receives records from a bound invocation.

Known limits

  • Telemetry is in-memory, per worker. It is not aggregated across workers and is lost on worker restart.
  • The unscoped store is never merged into a tenant view; it exists only for direct use.
  • No claim of certification; independent review and two-Workspace invocation acceptance are still required.