fix(feishu): defer the lark_oapi import off the startup path (salvage #57657) - #77514
Merged
kshitijk4poor merged 3 commits intoAug 3, 2026
Merged
Conversation
Salvage of NousResearch#57657, ported onto the plugin layout (the adapter moved from gateway/platforms/feishu.py to plugins/platforms/feishu/adapter.py since the PR's base). lark_oapi takes seconds to import and holds the GIL doing it; the module-level import made every gateway boot pay that cost even with Feishu unconfigured. - _load_lark_oapi() with double-checked locking binds the SDK globals on first use; connect() and _standalone_send() call it via asyncio.to_thread so the loop never blocks on the import. - probe_bot() also calls _load_lark_oapi() (sync context) so the SDK probe path is preserved rather than silently degrading to the HTTP fallback before a first connect. - check_feishu_requirements() is install-only and no longer rebinds globals; test_feishu.py gets a setUpModule that binds them eagerly for tests that inject fake clients. Includes the dedicated lazy-import test file (check-does-not-import, connect-loads-on-worker-thread).
kshitijk4poor
enabled auto-merge (rebase)
August 3, 2026 08:51
CI exposed the whole class: feishu tests across MANY files (thread routing, text batching, sdk executor, ...) inject a mock _client and skip connect(), so the deferred import leaves the request-builder globals None. Replace the single-file setUpModule with a session-scoped autouse conftest fixture that binds the globals once when lark_oapi is installed; when it isn't, the affected tests already skip via their own skipUnless guards. Full tests/gateway run: zero failures beyond main's pre-existing baseline (sorted failure-diff).
The no-SDK fallback guards check '"Name" in globals()' — correct on main where a failed module-level import leaves those names undefined, but the deferred-import port pre-binds every SDK name to None, so the guard was always true and the fallback paths called .builder() on None (AttributeError) wherever lark_oapi isn't installed. Local runs passed because lark IS installed here; CI's default env has no feishu extra. Rewrote all 14 guards to 'is not None', which is correct under both conditions. Verified by simulating CI with a lark-blocking meta_path hook: 74 passed, 18 skipped (the skipUnless set), zero failures.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvages #57657 by @baau — ported onto the plugin layout with authorship preserved (the adapter moved from gateway/platforms/feishu.py to plugins/platforms/feishu/adapter.py since the PR's base, ~4,500 commits back, so this is a port rather than a cherry-pick).
Context — what this fixes, for whom
Every gateway user, whether or not they use Feishu:
lark_oapiis a heavy SDK that takes seconds to import and holds the GIL while doing it, and the adapter imported it at module level — so every gateway boot paid that cost during startup's most GIL-sensitive window. This was the surviving canonical of a duplicate pair (#68849 was closed in its favor): 23cb26c fixed the desktop-boot symptom, but the eager import itself remained.What the fix does (from #57657, kept intact through the port)
_load_lark_oapi()binds the SDK globals on first use, with a threading lock + double-checked locking;connect()and_standalone_send()invoke it viaasyncio.to_threadso the event loop never blocks on the importcheck_feishu_requirements()becomes install-only (lazy_deps.ensure) — no import, no global rebindingReview findings folded in (the port's two additions)
FEISHU_AVAILABLEstays False until first connect, soprobe_bot()would have silently degraded to its HTTP fallback. It now calls_load_lark_oapi()first (sync context — it's a blocking helper already), keeping the SDK probe path. This was the prior triage's Medium finding; call-site enumeration confirmed probe_bot was the only consumer left stranded.test_feishu.py's existing tests inject fake clients into the module globals, which the PR's install-only check no longer binds — asetUpModulebinds them eagerly for the test process (7 failures otherwise).Verification
tests/gateway/test_feishu.py+test_feishu_lazy_import.py: 77 passed, 1 skipped on current mainCloses #57657 (superseded by this salvage — original author credited via commit authorship).