From 8ba8a220b6b7fe758d29e347f8954abe0f657178 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 1 Jun 2022 12:59:44 +0200 Subject: [PATCH] Playwright - Correctly close browser context/sessions on exceptions --- changedetectionio/content_fetcher.py | 24 ++++++++++++++++++++++-- changedetectionio/update_worker.py | 4 ++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/changedetectionio/content_fetcher.py b/changedetectionio/content_fetcher.py index 528a7a2d..78446f5b 100644 --- a/changedetectionio/content_fetcher.py +++ b/changedetectionio/content_fetcher.py @@ -14,6 +14,14 @@ class EmptyReply(Exception): return pass +class ScreenshotUnavailable(Exception): + def __init__(self, status_code, url): + # Set this so we can use it in other parts of the app + self.status_code = status_code + self.url = url + return + pass + class ReplyWithContentButNoText(Exception): def __init__(self, status_code, url): # Set this so we can use it in other parts of the app @@ -295,12 +303,18 @@ class base_html_playwright(Fetcher): extra_wait = int(os.getenv("WEBDRIVER_DELAY_BEFORE_CONTENT_READY", 5)) + self.render_extract_delay page.wait_for_timeout(extra_wait * 1000) except playwright._impl._api_types.TimeoutError as e: + context.close() + browser.close() raise EmptyReply(url=url, status_code=None) if response is None: + context.close() + browser.close() raise EmptyReply(url=url, status_code=None) if len(page.content().strip()) == 0: + context.close() + browser.close() raise EmptyReply(url=url, status_code=None) # Bug 2(?) Set the viewport size AFTER loading the page @@ -316,11 +330,17 @@ class base_html_playwright(Fetcher): page.evaluate("var css_filter=''") self.xpath_data = page.evaluate("async () => {" + self.xpath_element_js + "}") + # Bug 3 in Playwright screenshot handling # Some bug where it gives the wrong screenshot size, but making a request with the clip set first seems to solve it # JPEG is better here because the screenshots can be very very large - page.screenshot(type='jpeg', clip={'x': 1.0, 'y': 1.0, 'width': 1280, 'height': 1024}) - self.screenshot = page.screenshot(type='jpeg', full_page=True, quality=92) + try: + page.screenshot(type='jpeg', clip={'x': 1.0, 'y': 1.0, 'width': 1280, 'height': 1024}) + self.screenshot = page.screenshot(type='jpeg', full_page=True, quality=92) + except Exception as e: + context.close() + browser.close() + raise ScreenshotUnavailable(url=url, status_code=None) context.close() browser.close() diff --git a/changedetectionio/update_worker.py b/changedetectionio/update_worker.py index a46c63c9..40a66a49 100644 --- a/changedetectionio/update_worker.py +++ b/changedetectionio/update_worker.py @@ -63,6 +63,10 @@ class update_worker(threading.Thread): err_text = "EmptyReply: Status Code {}".format(e.status_code) self.datastore.update_watch(uuid=uuid, update_obj={'last_error': err_text, 'last_check_status': e.status_code}) + except content_fetcher.ScreenshotUnavailable as e: + err_text = "Screenshot unavailable, page did not render fully in the expected time" + self.datastore.update_watch(uuid=uuid, update_obj={'last_error': err_text, + 'last_check_status': e.status_code}) except Exception as e: self.app.logger.error("Exception reached processing watch UUID: %s - %s", uuid, str(e)) self.datastore.update_watch(uuid=uuid, update_obj={'last_error': str(e)})