Skip to content

Commit 8bd7882

Browse files
wu-shengclaude
andcommitted
fix(ci): repair sw_grpc on grpcio 1.83 and sw_websockets under uvicorn >= 0.50
Both plugin tests have been failing on every master CI run since 88d30ab; neither failure changes the supported version scope. - sw_grpc (grpcio == 1.*): grpcio 1.83.0 added an isinstance(x, Channel) validation in grpc.aio._channel resolved from the module global, which the plugin had rebound to a factory function -> TypeError on every aio stub creation. Replace the factory with a Channel subclass; verified against grpcio 1.83.0 and 1.82.1 with full trace validation. - sw_websockets (10.3/10.4): uvicorn 0.50.0 (2026-07-04) removed its legacy websockets fallback and unconditionally imports websockets.server.ServerProtocol (websockets >= 11 only), so the unpinned test harness crashed at startup with websockets 10.x. Pin uvicorn < 0.50 in the test compose; websockets 10.3/10.4 stay tested. Also extend the support matrix with websockets 17.0.1 (latest), which passes span validation with the plugin unmodified. Note: both uvicorn < 0.50's server impl and the plugin's client instrumentation rest on websockets.legacy (deprecated since websockets 14); when upstream removes it the plugin needs a rewrite against websockets.asyncio. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent beeac20 commit 8bd7882

4 files changed

Lines changed: 30 additions & 23 deletions

File tree

docs/en/setup/Plugins.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ or a limitation of SkyWalking auto-instrumentation (welcome to contribute!)
5151
| [urllib3](https://urllib3.readthedocs.io/en/latest/) | Python >=3.12 - NOT SUPPORTED YET; Python >=3.10 - ['1.26', '1.25']; | `sw_urllib3` |
5252
| [urllib3](https://urllib3.readthedocs.io/en/latest/) | Python >=3.12 - ['2.3', '2.0']; | `sw_urllib3_v2` |
5353
| [urllib_request](https://docs.python.org/3/library/urllib.request.html) | Python >=3.7 - ['*']; | `sw_urllib_request` |
54-
| [websockets](https://websockets.readthedocs.io) | Python >=3.7 - ['10.3', '10.4']; | `sw_websockets` |
54+
| [websockets](https://websockets.readthedocs.io) | Python >=3.7 - ['10.3', '10.4', '17.0.1']; | `sw_websockets` |
5555
### Notes
5656
- The celery server running with "celery -A ..." should be run with the HTTP protocol
5757
as it uses multiprocessing by default which is not compatible with the gRPC protocol implementation

skywalking/plugins/sw_grpc.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -448,25 +448,32 @@ async def intercept_stream_stream(
448448
) -> grpc.aio._call.StreamStreamCall:
449449
return await self._intercept(continuation, client_call_details, request_iterator)
450450

451-
def _sw_grpc_aio_channel_factory(
452-
target: str,
453-
options: grpc.aio.ChannelArgumentType,
454-
credentials: Optional[grpc.ChannelCredentials],
455-
compression: Optional[grpc.Compression],
456-
interceptors: Optional[Sequence[grpc.aio.ClientInterceptor]],
457-
):
458-
if target == config.agent_collector_backend_services:
459-
return _aio_grpc_channel(target, options, credentials, compression, interceptors)
460-
_sw_interceptors: List[grpc.aio.ClientInterceptor] = [
461-
_AioClientUnaryUnaryInterceptor(target),
462-
_AioClientUnaryStreamInterceptor(target),
463-
_AioClientStreamUnaryInterceptor(target),
464-
_AioClientStreamStreamInterceptor(target),
465-
]
466-
_sw_interceptors.extend(interceptors or [])
467-
return _aio_grpc_channel(target, options, credentials, compression, _sw_interceptors)
468-
469-
_aio_channel.Channel = _sw_grpc_aio_channel_factory
451+
# Must remain a class assigned to the module-global name `Channel`:
452+
# since grpcio 1.83.0, grpc.aio._channel._BaseMultiCallable.__init__ validates
453+
# `isinstance(self._references[0], Channel)` against this module global, so
454+
# rebinding it to a plain factory function raises
455+
# `TypeError: isinstance() arg 2 must be a type, ...` on every stub creation.
456+
class _SWAioChannel(_aio_grpc_channel):
457+
def __init__(
458+
self,
459+
target: str,
460+
options: grpc.aio.ChannelArgumentType,
461+
credentials: Optional[grpc.ChannelCredentials],
462+
compression: Optional[grpc.Compression],
463+
interceptors: Optional[Sequence[grpc.aio.ClientInterceptor]],
464+
):
465+
if target != config.agent_collector_backend_services:
466+
_sw_interceptors: List[grpc.aio.ClientInterceptor] = [
467+
_AioClientUnaryUnaryInterceptor(target),
468+
_AioClientUnaryStreamInterceptor(target),
469+
_AioClientStreamUnaryInterceptor(target),
470+
_AioClientStreamStreamInterceptor(target),
471+
]
472+
_sw_interceptors.extend(interceptors or [])
473+
interceptors = _sw_interceptors
474+
super().__init__(target, options, credentials, compression, interceptors)
475+
476+
_aio_channel.Channel = _SWAioChannel
470477

471478
install_async_client()
472479
install_async_server()

skywalking/plugins/sw_websockets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
link_vector = ['https://websockets.readthedocs.io']
2222
support_matrix = {
2323
'websockets': {
24-
'>=3.7': ['10.3', '10.4']
24+
'>=3.7': ['10.3', '10.4', '17.0.1']
2525
}
2626
}
2727
note = """The websocket instrumentation only traces client side connection handshake,

tests/plugin/http/sw_websockets/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ services:
3434
depends_on:
3535
collector:
3636
condition: service_healthy
37-
command: ['bash', '-c', 'pip install fastapi uvicorn && pip install -r /app/requirements.txt && sw-python run python3 /app/services/provider.py']
37+
command: ['bash', '-c', 'pip install fastapi "uvicorn<0.50" && pip install -r /app/requirements.txt && sw-python run python3 /app/services/provider.py']
3838
healthcheck:
3939
test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091"]
4040
interval: 5s
@@ -52,7 +52,7 @@ services:
5252
- 9090:9090
5353
volumes:
5454
- .:/app
55-
command: ['bash', '-c', 'pip install fastapi uvicorn && pip install -r /app/requirements.txt && sw-python run python3 /app/services/consumer.py']
55+
command: ['bash', '-c', 'pip install fastapi "uvicorn<0.50" && pip install -r /app/requirements.txt && sw-python run python3 /app/services/consumer.py']
5656
depends_on:
5757
collector:
5858
condition: service_healthy

0 commit comments

Comments
 (0)