fix(gateway): skip credential-less WhatsApp on secondary multiplex profiles
_start_one_profile_adapters skipped only Platform.RELAY as shared process-level ingress. WhatsApp is the same shape: the bridge is one authenticated session tied to a single phone number, so a secondary profile has no credential of its own to bring; constructing an adapter for it only produced a connect/retry loop that stalled startup for every profile queued behind it. Treat WhatsApp like Relay -- the active profile owns the connection and route-stamped source.profile fans inbound turns out to secondary profiles. Salvage of #69042 (narrowed by its author to this one behavioral line); test re-expressed on the current secondary-startup fixtures. Co-authored-by: sshawn <28279366+lsshawn@users.noreply.github.com>
This commit is contained in:
+9
-4
@@ -17146,12 +17146,17 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
||||
platform.value,
|
||||
)
|
||||
continue
|
||||
# Relay is shared process-level ingress in multiplex mode. The
|
||||
# active profile owns the one connection; connector-stamped
|
||||
# source.profile routes inbound turns to secondary profiles.
|
||||
# Relay and WhatsApp are shared process-level ingress in multiplex
|
||||
# mode: one connection owned by the active profile, with
|
||||
# route-stamped source.profile fanning inbound turns out to
|
||||
# secondary profiles. The WhatsApp bridge is a single authenticated
|
||||
# session tied to one phone number -- a secondary profile has no
|
||||
# credential of its own to bring, so constructing an adapter for it
|
||||
# only yields a connect/retry loop that stalls startup for every
|
||||
# profile queued behind it.
|
||||
if (
|
||||
getattr(self.config, "multiplex_profiles", False)
|
||||
and platform is Platform.RELAY
|
||||
and platform in (Platform.RELAY, Platform.WHATSAPP)
|
||||
):
|
||||
continue
|
||||
try:
|
||||
|
||||
@@ -1034,6 +1034,43 @@ class TestSecondaryProfileConfigHandling:
|
||||
assert "reviewer" in str(exc_info.value)
|
||||
assert "reviewer" not in runner._profile_adapters
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_secondary_profile_adapter_start_skips_whatsapp(self, monkeypatch):
|
||||
"""WhatsApp is shared process-level ingress like Relay: the bridge is
|
||||
one authenticated session tied to a single phone number, so a
|
||||
credential-less secondary profile must be skipped (not stall startup
|
||||
in a connect/retry loop) while its other platforms start normally."""
|
||||
runner = _secondary_recovery_runner()
|
||||
direct = _SecondaryRecoveryAdapter()
|
||||
_install_secondary_reconnect_context(monkeypatch, runner, direct)
|
||||
monkeypatch.setattr(
|
||||
"gateway.config.load_gateway_config",
|
||||
lambda: GatewayConfig(
|
||||
multiplex_profiles=True,
|
||||
platforms={
|
||||
Platform.WHATSAPP: PlatformConfig(enabled=True),
|
||||
Platform.DISCORD: PlatformConfig(enabled=True, token="profile-token"),
|
||||
},
|
||||
),
|
||||
)
|
||||
factory_calls = []
|
||||
|
||||
def _create_adapter(platform, config):
|
||||
factory_calls.append(platform)
|
||||
return direct
|
||||
|
||||
async def _connect(adapter, platform):
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(runner, "_create_adapter", _create_adapter)
|
||||
monkeypatch.setattr(runner, "_connect_initial_adapter_with_timeout", _connect)
|
||||
|
||||
connected = await runner._start_one_profile_adapters("clientbot", "/tmp/x", {})
|
||||
|
||||
assert connected == 1
|
||||
assert factory_calls == [Platform.DISCORD]
|
||||
assert runner._profile_adapters["clientbot"] == {Platform.DISCORD: direct}
|
||||
|
||||
|
||||
class TestSecondaryProfileHookRegistration:
|
||||
"""A secondary profile's own `hooks:` block must register on ITS
|
||||
|
||||
Reference in New Issue
Block a user