SIGN IN SIGN UP

feat: enterprise readiness + telemetry exports (#14663)

* feat: enterprise readiness + telemetry exports

- health_check_router: add /healthz endpoint + _enterprise_readiness_checks
  registry (empty = no behaviour change); enterprise plugins append an async
  check callable; any \"error:\" result returns HTTP 503 so the pod goes Unready
- telemetry/run_event_store: docstring marks pop_all() and append_run_event()
  as stable extension points with deprecation-cycle requirement
- telemetry/__init__: re-exports both functions at the stable package path
  (from langflow.services.telemetry import pop_all, append_run_event)

Enterprise bridge should update its import to use the stable path once this merges.

* fix: dont swallow telemetry hook exceptions

Replace contextlib.suppress(Exception) with try/except + logger.awarning
in both the sync and streaming finally blocks of workflow_execution.py.

Silent suppression prevented enterprise metering (append_run_event) from
being reached when get_telemetry_service() or RunPayload() raised before
the call — queue depth stayed 0 with no log evidence.

Both paths now log a WARNING with full stack trace on failure while still
protecting the user workflow from a broken telemetry hook.

Also removes the stale `import contextlib as _cl` inside the sync finally
block (module-level import already present).

Fixes: enterprise metering queue not populated after /api/v2/workflows runs

* fix: enforce run_event_store public API contract

Add signature and import-path assertions to test_telemetry_reexports so
that any rename, removal, or arity change in the two stable extension
points (pop_all, append_run_event) breaks CI before enterprise consumers
are silently broken:

- test_pop_all_takes_no_parameters: fails if a required param is added
- test_append_run_event_accepts_single_payload_param: fails if 'payload'
  is renamed or the required param list changes
- test_stable_import_path_resolves: fails if either symbol is dropped
  from langflow.services.telemetry.__all__ or becomes non-callable

* test: add coverage for timeout, chat failure

add coverage for timeout, chat failure

* test: tighten tests and fix timeout

tighten signature contracts and fix timeout test for enterprise readiness checks

* fix: remove health_check_router re-export

The APIRouter instance shadowed the submodule name, causing unittest.mock.patch
to resolve 'langflow.api.health_check_router.get_chat_service' against the router
object instead of the module, breaking test_enterprise_readiness_checks.

main.py now imports health_check_router directly from the submodule.

* fix: catch asyncio.TimeoutError

On Python <=3.10 asyncio.wait_for raises asyncio.TimeoutError which does not
inherit from the built-in TimeoutError, so the except clause missed it and the
broad except Exception swallowed it silently — no 503 was raised.

Catching both types covers all supported Python versions (3.10-3.14).

* fix: relax roundtrip assertion to semantic equality

Replace `drained[0] is payload` with `drained[0].model_dump() == payload.model_dump()`
in test_append_then_pop_roundtrip. Preserves the append/pop payload contract
while allowing implementations that copy or serialize the payload.

* chore: remove unneeded comment

remove unneeded comment

* chore: fix DRY, magic string, log exposure

- Extract DB + chat probe block into _probe_services(session) helper;
  health_check() and healthz() now delegate to it (fixes DRY violation)
- Add _HEALTH_CHECK_PROBE_KEY module constant; remove duplicate UUID
  literal "da93c2bd-c857-4b10-8c8c-60988103320f" (fixes magic string)
- Drop `result` from enterprise readiness error warning to prevent
  tenant/license detail leakage in logs (fixes log exposure)
- Simplify triple-nested getattr to getattr(__qualname__, type.__name__)
- Add comment on (TimeoutError, asyncio.TimeoutError) tuple explaining
  Python 3.10 compatibility rationale
A
Adam-Aghili committed
eb08ae2e3204dbcd09007aa18f41b7633883c47f
Parent: 97ced62
Committed by GitHub <noreply@github.com> on 8/21/2026, 4:04:37 AM