python-websockets / websockets

Library for building WebSocket servers and clients in Python
https://websockets.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
5.07k stars 506 forks source link

ResourceWarning: unclosed <...> #1375

Closed FrankC01 closed 1 year ago

FrankC01 commented 1 year ago

mac -> Ventura 13.4.1 (22F82) chip -> Apple M1 Max Python 3.10.6 python-websockets version -> 11.0.3

When I run script from command line, after it exits I'm getting: sys:1: ResourceWarning: unclosed <ssl.SSLSocket fd=10, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('10.0.0.138', 55946), raddr=('45.77.125.233', 443)>

Despite expected closing (see log snippet at EOM)

Here is the main listener:

    async def _subscription_listener(
        self,
        builder: Union[SubscribeEvent, SubscribeTransaction],
        handler: Union[
            Callable[[SubscribedEvent, int, int], Any],
            Callable[[SubscribedTransaction, int, int], Any],
        ],
    ) -> SuiRpcResult:
        """_subscription_listener Sets up websocket subscription and calls _subscription_drive.

        :param builder: The subscription builder submitted for creating subscription filters.
        :type builder: SubscribedEvent
        :param handler: The function called for each received event.
        :type handler: Callable[[SubscribedEvent, int], Any]
        :return: Result of subscription event handling.
        :rtype: SuiRpcResult
        """
        try:
            if self.config.local_config:
                async with ws_connect(
                    self.config.socket_url,
                    extra_headers=self._ADDITIONL_HEADER,
                ) as websock:
                    res = await self._subscription_drive(
                        self._PAYLOAD_TEMPLATE.copy(),
                        builder,
                        websock,
                        handler,
                    )
                    logging.info(
                        f"Listener returning in shutdown: {self._in_shutdown}"
                    )
                    await websock.close()
                    return res
            else:
                # Filter the warning about deprecated SSL context
                warnings.simplefilter("ignore")
                async with ws_connect(
                    self.config.socket_url,
                    extra_headers=self._ADDITIONL_HEADER,
                    ssl=ssl.SSLContext(ssl.PROTOCOL_SSLv23),
                ) as websock:
                    warnings.simplefilter("default")
                    res = await self._subscription_drive(
                        self._PAYLOAD_TEMPLATE.copy(),
                        builder,
                        websock,
                        handler,
                    )
                    logging.info(
                        f"Listener returning in shutdown: {self._in_shutdown}"
                    )
                    await websock.close()
                    return res
        except AttributeError as axc:
            logging.warning(
                f"AttributeError occured for shutdown -> {self._in_shutdown}"
            )
            return SuiRpcResult(False, "Attribute Error", axc)
        except Exception as axc:
            logging.warning(
                f"Exception occured for shutdown -> {self._in_shutdown}"
            )
            return SuiRpcResult(False, "Exception", axc)

Relevant log data:

2023-06-23 07:33:28,337 [INFO] Listener returning in shutdown: True
2023-06-23 07:33:28,337 [DEBUG] = connection is CLOSING
2023-06-23 07:33:28,338 [DEBUG] > CLOSE 1000 (OK) [2 bytes]
2023-06-23 07:33:28,462 [DEBUG] < CLOSE 1000 (OK) [2 bytes]
2023-06-23 07:33:28,464 [DEBUG] = connection is CLOSED
2023-06-23 07:33:28,465 [DEBUG] x closing TCP connection
aaugustin commented 1 year ago

Indeed, this shouldn't happen.

await websock.close() is redundant — assuming ws_connect is from websockets.client import connect as ws_connect, the context manager takes care of that for you.

Can you confirm that it happens only when TLS is enabled i.e. in the else: branch of the if self.config.local_config:?

FrankC01 commented 1 year ago

Yes, how would I confirm that? I know for certain the code path is through else branch :

else:
                # Filter the warning about deprecated SSL context
                warnings.simplefilter("ignore")
                async with ws_connect(
                    self.config.socket_url,
                    extra_headers=self._ADDITIONL_HEADER,
                    ssl=ssl.SSLContext(ssl.PROTOCOL_SSLv23),
                ) as websock:
                    warnings.simplefilter("default")
                    res = await self._subscription_drive(
                        self._PAYLOAD_TEMPLATE.copy(),
                        builder,
                        websock,
                        handler,
                    )
                    logging.info(
                        f"Listener returning in shutdown: {self._in_shutdown}"
                    )
                    await websock.close()
                    return res
FrankC01 commented 1 year ago

More information:

For non-websocket IO I'm using HTTPX.

In the handler of events received, when I add a call vis-a-vis synchronous httpx, then the error occurs.'

I added a close call to the httpx connection and that resolved the error message noted above.

aaugustin commented 1 year ago

OK -- so the problem seemed to be with the HTTP connection, not the websockets connection.

FrankC01 commented 1 year ago

Yes, so it seems....