Commit 5eb38f99 authored by Barkin Simsek's avatar Barkin Simsek 🐢
Browse files

Trying to make tenacity work

parent 801e5dd9
Pipeline #7099 failed with stage
in 1 minute and 28 seconds
......@@ -6,5 +6,5 @@ disallow_untyped_calls = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
[mypy-pytest.*,sqlalchemy.*,stem.*,docker.*,port_for.*,setuptools.*,sqlalchemy_utils.*,selenium.*,country_converter.*]
[mypy-pytest.*,sqlalchemy.*,stem.*,docker.*,port_for.*,setuptools.*,sqlalchemy_utils.*,selenium.*,country_converter.*,tenacity.*]
ignore_missing_imports = True
\ No newline at end of file
......@@ -474,7 +474,7 @@ ignore-comments=no
ignore-docstrings=no
# Ignore imports when computing similarities.
ignore-imports=no
ignore-imports=yes
[VARIABLES]
......
import sys
import time
import logging
from typing import Optional
from captchamonitor.utils.config import Config
......@@ -7,6 +6,13 @@ from captchamonitor.utils.database import Database
from captchamonitor.utils.exceptions import DatabaseInitError, ConfigInitError
from captchamonitor.core.worker import Worker
from captchamonitor.utils.small_scripts import node_id
from captchamonitor.utils.small_scripts import (
Retrying,
stop_after_attempt,
wait_fixed,
retry_if_exception_type,
after_log,
)
class CaptchaMonitor:
......@@ -24,35 +30,39 @@ class CaptchaMonitor:
# Private class attributes
self.__logger = logging.getLogger(__name__)
self.__node_id: str = str(node_id())
self.__database: Database
self.__config: Config
self.__retryer: Retrying = Retrying(
stop=stop_after_attempt(3),
wait=wait_fixed(3),
retry=(retry_if_exception_type(DatabaseInitError)),
after=after_log(self.__logger, logging.DEBUG),
reraise=True,
)
try:
self.__config: Config = Config()
self.__config = Config()
except ConfigInitError:
self.__logger.warning(
self.__logger.critical(
"Could not initialize CAPTCHA Monitor since some configuration values are missing, exitting"
)
sys.exit(1)
# Try connecting to the database 3 times
for _ in range(3):
try:
self.__database: Database = Database(
self.__config["db_host"],
self.__config["db_port"],
self.__config["db_name"],
self.__config["db_user"],
self.__config["db_password"],
verbose,
)
break
except DatabaseInitError:
self.__logger.warning("Could not connect to the database, retrying")
time.sleep(3)
# Try connecting to the database
try:
self.__database = self.__retryer(
Database,
self.__config["db_host"],
self.__config["db_port"],
self.__config["db_name"],
self.__config["db_user"],
self.__config["db_password"],
verbose,
)
# Check if database connection was made
if not hasattr(self, "__database"):
self.__logger.warning(
except DatabaseInitError:
self.__logger.critical(
"Could not initialize CAPTCHA Monitor since I couldn't connect to the database, exitting"
)
sys.exit(1)
......
import os
import shutil
import time
import logging
from typing import Optional, Union, Any
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from captchamonitor.utils.config import Config
from captchamonitor.utils.tor_launcher import TorLauncher
from captchamonitor.utils.small_scripts import (
Retrying,
stop_after_attempt,
wait_fixed,
retry_if_exception_type,
after_log,
)
from captchamonitor.utils.exceptions import (
FetcherConnectionInitError,
FetcherURLFetchError,
......@@ -68,6 +74,13 @@ class BaseFetcher:
self._desired_capabilities: webdriver.DesiredCapabilities
self._num_retries_on_fail: int = 3
self._delay_in_seconds_between_retries: int = 3
self._retryer: Retrying = Retrying(
stop=stop_after_attempt(3),
wait=wait_fixed(3),
retry=(retry_if_exception_type(ConnectionRefusedError)),
after=after_log(self._logger, logging.DEBUG),
reraise=True,
)
# Get the extension path
self._har_export_extension_xpi = self._config["asset_har_export_extension_xpi"]
......@@ -127,32 +140,21 @@ class BaseFetcher:
:raises FetcherConnectionInitError: If it wasn't able to connect to the webdriver
"""
# Connect to browser container
connected = False
for _ in range(self._num_retries_on_fail):
try:
self.driver = webdriver.Remote(
desired_capabilities=desired_capabilities,
command_executor=command_executor,
options=options,
)
connected = True
break
except ConnectionRefusedError as exception:
self._logger.debug(
"Unable to connect to the %s container, retrying: %s",
container_name,
exception,
)
time.sleep(self._delay_in_seconds_between_retries)
# Check if connection to selenium container was successfull
if not connected:
try:
self.driver = self._retryer(
webdriver.Remote,
desired_capabilities=desired_capabilities,
command_executor=command_executor,
options=options,
)
except ConnectionRefusedError as exception:
self._logger.warning(
"Could not connect to the %s container after many retries",
"Could not connect to the %s container after many retries: %s",
container_name,
exception,
)
raise FetcherConnectionInitError
raise FetcherConnectionInitError from exception
# Set driver timeout
self.driver.set_page_load_timeout(self.page_timeout)
......
import os
import pickle
from typing import cast, Any
import docker
import tenacity
# Add typing to tenacity functions
Retrying = cast(Any, tenacity.Retrying)
retry = cast(Any, tenacity.retry)
stop_after_attempt = cast(Any, tenacity.stop_after_attempt)
wait_fixed = cast(Any, tenacity.wait_fixed)
retry_if_exception_type = cast(Any, tenacity.retry_if_exception_type)
after_log = cast(Any, tenacity.after_log)
# Deep copies objects
deep_copy = lambda obj: pickle.loads(pickle.dumps(obj))
......
import logging
import time
import random
from typing import Optional, Any, List
import docker
......@@ -9,6 +8,14 @@ import stem.control
from stem.util.log import get_logger
from stem.control import Controller
from captchamonitor.utils.config import Config
from captchamonitor.utils.small_scripts import (
retry,
Retrying,
stop_after_attempt,
wait_fixed,
retry_if_exception_type,
after_log,
)
from captchamonitor.utils.exceptions import (
TorLauncherInitError,
StemConnectionInitError,
......@@ -39,8 +46,16 @@ class TorLauncher:
self.__logger = logging.getLogger(__name__)
self.__config: Config = config
self.__circuit_id: Controller.new_circuit
self.__num_retries_on_fail: int = 3
self.__delay_in_seconds_between_retries: int = 3
self.__retryer: Retrying = Retrying(
stop=stop_after_attempt(3),
wait=wait_fixed(3),
retry=(
retry_if_exception_type(stem.SocketError)
| retry_if_exception_type(stem.DescriptorUnavailable)
),
after=after_log(self.__logger, logging.DEBUG),
reraise=True,
)
try:
self.__docker_network_name = self.__config["docker_network"]
......@@ -130,44 +145,54 @@ class TorLauncher:
self.control_port,
)
@retry(
stop=stop_after_attempt(3),
wait=wait_fixed(3),
retry=retry_if_exception_type(stem.SocketError),
reraise=True,
)
def __get_stem_controller_from_port(self) -> Controller:
return Controller.from_port(
address=str(self.ip_address), port=int(self.control_port)
)
def __bind_stem_to_tor_container(self) -> None:
"""
Binds Tor Stem to the Tor Container launched earlier
:raises StemConnectionInitError: If stem wasn't initialized correctly
"""
self.__tor_password = self.__config["docker_tor_authentication_password"]
# Try connecting multiple times
connected = False
for _ in range(self.__num_retries_on_fail):
try:
self.__controller = Controller.from_port(
address=str(self.ip_address), port=int(self.control_port)
)
self.__controller.authenticate(password=self.__tor_password)
connected = True
break
except stem.SocketError as exception:
self.__logger.debug(
"Unable to connect to the Tor Container, retrying: %s",
exception,
)
time.sleep(self.__delay_in_seconds_between_retries)
# Check if connection was successfull
if not connected:
# Try connecting to the Tor container
try:
self.__controller = self.__get_stem_controller_from_port()
except stem.SocketError as exception:
self.__logger.warning(
"Could not connect to the Tor Container after many retries"
"Could not connect to the Tor Container after many retries: %s",
exception,
)
raise StemConnectionInitError
raise StemConnectionInitError from exception
# Authenticate
self.__controller.authenticate(password=self.__tor_password)
self.__logger.debug(
"Connected to the Tor Container, the Tor version running on the container is %s",
self.__controller.get_version(),
)
@retry(
stop=stop_after_attempt(3),
wait=wait_fixed(3),
retry=retry_if_exception_type(stem.DescriptorUnavailable),
reraise=True,
)
def __get_network_statuse_from_stem(self) -> List[object]:
return self.__controller.get_network_statuses
def update_relay_descriptors(self) -> None:
"""
Gets a copy of the current relay descriptors from the Tor Container using
......@@ -175,27 +200,18 @@ class TorLauncher:
:raises StemDescriptorUnavailableError: If stem wasn't able to get relay descriptors
"""
# Try connecting multiple times
connected = False
for _ in range(self.__num_retries_on_fail):
try:
self.relay_fingerprints = [
desc.fingerprint
for desc in self.__controller.get_network_statuses()
]
connected = True
break
except stem.DescriptorUnavailable as exception:
self.__logger.debug(
"Unable to get relay descriptors, retrying: %s", exception
)
time.sleep(self.__delay_in_seconds_between_retries)
# Check if connection was successfull
if not connected:
self.__logger.warning("Could not get relay descriptors after many retries")
raise StemDescriptorUnavailableError
# Try retrieving the descriptors
try:
network_statuses = self.__get_network_statuse_from_stem()
except stem.DescriptorUnavailable as exception:
self.__logger.warning(
"Could not get relay descriptors after many retries: %s",
exception,
)
raise StemDescriptorUnavailableError from exception
self.relay_fingerprints = [desc.fingerprint for desc in network_statuses]
# pylint: disable=E1101
def __attach_stream(self, stream: stem.control.EventType.STREAM) -> None:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment