Skip to content

Instantly share code, notes, and snippets.

@zxsleebu
Created June 14, 2024 08:03
Show Gist options
  • Save zxsleebu/3602dff4be43c73e32e7d2884b7a1ac3 to your computer and use it in GitHub Desktop.
Save zxsleebu/3602dff4be43c73e32e7d2884b7a1ac3 to your computer and use it in GitHub Desktop.
nodriver memory leak fix
from asyncio import iscoroutine, iscoroutinefunction
import logging
import json
import asyncio
import itertools
from nodriver import cdp
import nodriver as uc
logger = logging.getLogger("uc.connection")
async def listener_loop(self):
while True:
try:
msg = await asyncio.wait_for(
self.connection.websocket.recv(), self.time_before_considered_idle
)
except asyncio.TimeoutError:
self.idle.set()
# breathe
# await asyncio.sleep(self.time_before_considered_idle / 10)
continue
except (Exception,) as e:
# break on any other exception
# which is mostly socket is closed or does not exist
# or is not allowed
logger.debug(
"connection listener exception while reading websocket:\n%s", e
)
break
if not self.running:
# if we have been cancelled or otherwise stopped running
# break this loop
break
# since we are at this point, we are not "idle" anymore.
self.idle.clear()
message = json.loads(msg)
if "id" in message:
# response to our command
if message["id"] in self.connection.mapper:
# get the corresponding Transaction
tx = self.connection.mapper[message["id"]]
logger.debug("got answer for %s", tx)
# complete the transaction, which is a Future object
# and thus will return to anyone awaiting it.
tx(**message)
self.connection.mapper.pop(message["id"])
else:
# probably an event
try:
event = cdp.util.parse_json_event(message)
event_tx = uc.connection.EventTransaction(event)
if not self.connection.mapper:
self.connection.__count__ = itertools.count(0)
event_tx.id = next(self.connection.__count__)
self.connection.mapper[event_tx.id] = event_tx
except Exception as e:
logger.info(
"%s: %s during parsing of json from event : %s"
% (type(e).__name__, e.args, message),
exc_info=True,
)
continue
except KeyError as e:
logger.info("some lousy KeyError %s" % e, exc_info=True)
continue
try:
if type(event) in self.connection.handlers:
callbacks = self.connection.handlers[type(event)]
else:
continue
if not len(callbacks):
continue
for callback in callbacks:
try:
if iscoroutinefunction(callback) or iscoroutine(callback):
await callback(event)
else:
callback(event)
except Exception as e:
logger.warning(
"exception in callback %s for event %s => %s",
callback,
event.__class__.__name__,
e,
exc_info=True,
)
raise
except asyncio.CancelledError:
break
except Exception:
raise
continue
#call this after imported nodriver
#uc_fix(*nodriver module*)
def uc_fix(uc: uc):
uc.core.connection.Listener.listener_loop = listener_loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment