fix(gateway): keep Feishu websocket off default executor

This commit is contained in:
JackJin
2026-08-05 15:27:13 +08:00
committed by Teknium
parent 957a8a287c
commit 5fbef868a9
2 changed files with 12 additions and 6 deletions
+1 -1
View File
@@ -3718,7 +3718,7 @@ class FeishuAdapter(BasePlatformAdapter):
# thread has an empty context = launch profile. connect() runs inside the profile scope # thread has an empty context = launch profile. connect() runs inside the profile scope
# under multiplex (and the supervisor task inherits it), so snapshot it here. # under multiplex (and the supervisor task inherits it), so snapshot it here.
self._ws_future = loop.run_in_executor( self._ws_future = loop.run_in_executor(
None, contextvars.copy_context().run, _run_official_feishu_ws_client, self._ws_client, self) self._get_sdk_executor(), contextvars.copy_context().run, _run_official_feishu_ws_client, self._ws_client, self)
async def _connect_webhook(self) -> None: async def _connect_webhook(self) -> None:
if not FEISHU_WEBHOOK_AVAILABLE: if not FEISHU_WEBHOOK_AVAILABLE:
+11 -5
View File
@@ -189,18 +189,22 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
"FEISHU_APP_ID": "cli_app", "FEISHU_APP_ID": "cli_app",
"FEISHU_APP_SECRET": "secret_app", "FEISHU_APP_SECRET": "secret_app",
}, clear=True) }, clear=True)
def test_connect_websocket_sets_channel_ua_tag(self): def test_connect_websocket_sets_channel_ua_tag_and_uses_owned_executor(self):
"""Verify that FeishuWSClient receives extra_ua_tags=["channel"]. """Verify the WebSocket client uses the channel tag and owned executor.
Without this UA tag the Feishu server does not push group @mention Without this UA tag the Feishu server does not push group @mention
events over the WebSocket transport. See events over the WebSocket transport. The long-lived client must also
stay off asyncio's shared default executor. See
https://github.com/NousResearch/hermes-agent/issues/50656 https://github.com/NousResearch/hermes-agent/issues/50656
https://github.com/NousResearch/hermes-agent/issues/78318
""" """
from gateway.config import PlatformConfig from gateway.config import PlatformConfig
from plugins.platforms.feishu.adapter import FeishuAdapter from plugins.platforms.feishu.adapter import FeishuAdapter
adapter = FeishuAdapter(PlatformConfig()) adapter = FeishuAdapter(PlatformConfig())
ws_client = SimpleNamespace() ws_client = SimpleNamespace()
owned_executor = object()
submitted_executors = []
with ( with (
patch("plugins.platforms.feishu.adapter.FEISHU_AVAILABLE", True), patch("plugins.platforms.feishu.adapter.FEISHU_AVAILABLE", True),
@@ -214,6 +218,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
patch("plugins.platforms.feishu.adapter.release_scoped_lock"), patch("plugins.platforms.feishu.adapter.release_scoped_lock"),
patch.object(adapter, "_hydrate_bot_identity", new=AsyncMock()), patch.object(adapter, "_hydrate_bot_identity", new=AsyncMock()),
patch.object(adapter, "_build_lark_client", return_value=SimpleNamespace()), patch.object(adapter, "_build_lark_client", return_value=SimpleNamespace()),
patch.object(adapter, "_get_sdk_executor", return_value=owned_executor),
): ):
_mock_event_dispatcher_builder(mock_handler_class) _mock_event_dispatcher_builder(mock_handler_class)
@@ -222,7 +227,8 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
future.set_result(None) future.set_result(None)
class _Loop: class _Loop:
def run_in_executor(self, *_args, **_kwargs): def run_in_executor(self, executor, *_args, **_kwargs):
submitted_executors.append(executor)
return future return future
def is_closed(self): def is_closed(self):
return False return False
@@ -243,6 +249,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase):
"FeishuWSClient must receive extra_ua_tags for group @mention delivery") "FeishuWSClient must receive extra_ua_tags for group @mention delivery")
self.assertEqual(call_kwargs["extra_ua_tags"], ["channel"], self.assertEqual(call_kwargs["extra_ua_tags"], ["channel"],
"extra_ua_tags must be ['channel'] to enable group event routing") "extra_ua_tags must be ['channel'] to enable group event routing")
self.assertEqual(submitted_executors, [owned_executor])
@patch.dict(os.environ, {}, clear=True) @patch.dict(os.environ, {}, clear=True)
@@ -2550,4 +2557,3 @@ class TestChatLockEviction(unittest.TestCase):
adapter = self._make_adapter() adapter = self._make_adapter()
self.assertIsInstance(adapter._chat_locks, _collections.OrderedDict) self.assertIsInstance(adapter._chat_locks, _collections.OrderedDict)