First pass EPP retry

This commit is contained in:
Erin 2023-12-05 11:35:08 -08:00
parent c569db24f3
commit 4a25642d8d
No known key found for this signature in database
GPG key ID: 1CAD275313C62460
4 changed files with 22 additions and 4 deletions

View file

@ -6,6 +6,8 @@ from django.utils.safestring import mark_safe
from registrar.templatetags.url_helpers import public_site_url from registrar.templatetags.url_helpers import public_site_url
from registrar.utility.errors import GenericError, GenericErrorCodes from registrar.utility.errors import GenericError, GenericErrorCodes
# comment out after testing
from epplibwrapper.errors import RegistryError
import requests import requests
@ -67,6 +69,9 @@ def check_domain_available(domain):
a match. If check fails, throws a RegistryError. a match. If check fails, throws a RegistryError.
""" """
Domain = apps.get_model("registrar.Domain") Domain = apps.get_model("registrar.Domain")
# TODO: remove this block it is used for testing on dev sandbox to verify error retry
if "bad" in domain:
raise RegistryError("Forced Registry Error from bad domain")
if domain.endswith(".gov"): if domain.endswith(".gov"):
return Domain.available(domain) return Domain.available(domain)
else: else:

View file

@ -17,7 +17,7 @@ except ImportError:
from django.conf import settings from django.conf import settings
from .cert import Cert, Key from .cert import Cert, Key
from .errors import LoginError, RegistryError from .errors import ErrorCode, LoginError, RegistryError
from .socket import Socket from .socket import Socket
from .utility.pool import EPPConnectionPool from .utility.pool import EPPConnectionPool
@ -115,7 +115,7 @@ class EPPLibWrapper:
except TransportError as err: except TransportError as err:
message = f"{cmd_type} failed to execute due to a connection error." message = f"{cmd_type} failed to execute due to a connection error."
logger.error(f"{message} Error: {err}", exc_info=True) logger.error(f"{message} Error: {err}", exc_info=True)
raise RegistryError(message) from err raise RegistryError(message, code=ErrorCode.TRANSPORT_ERROR) from err
except LoginError as err: except LoginError as err:
# For linter due to it not liking this line length # For linter due to it not liking this line length
text = "failed to execute due to a registry login error." text = "failed to execute due to a registry login error."
@ -159,11 +159,15 @@ class EPPLibWrapper:
self.start_connection_pool() self.start_connection_pool()
counter = 0 # we'll try 3 times counter = 0 # we'll try 3 times
logger.info("Counter set to: ", counter)
while True: while True:
try: try:
logger.info("Trying self._send(command)")
return self._send(command) return self._send(command)
except RegistryError as err: except RegistryError as err:
if err.should_retry() and counter < 3: logger.info("Exception found")
if counter < 3 and (err.should_retry() or err.is_transport_error()):
logger.info("Retrying transport error. Attempt #", counter)
counter += 1 counter += 1
sleep((counter * 50) / 1000) # sleep 50 ms to 150 ms sleep((counter * 50) / 1000) # sleep 50 ms to 150 ms
else: # don't try again else: # don't try again

View file

@ -4,13 +4,15 @@ from enum import IntEnum
class ErrorCode(IntEnum): class ErrorCode(IntEnum):
""" """
Overview of registry response codes from RFC 5730. See RFC 5730 for full text. Overview of registry response codes from RFC 5730. See RFC 5730 for full text.
- 0 System connection error
- 1000 - 1500 Success - 1000 - 1500 Success
- 2000 - 2308 Registrar did something silly - 2000 - 2308 Registrar did something silly
- 2400 - 2500 Registry did something silly - 2400 - 2500 Registry did something silly
- 2501 - 2502 Something malicious or abusive may have occurred - 2501 - 2502 Something malicious or abusive may have occurred
""" """
TRANSPORT_ERROR = 0
COMMAND_COMPLETED_SUCCESSFULLY = 1000 COMMAND_COMPLETED_SUCCESSFULLY = 1000
COMMAND_COMPLETED_SUCCESSFULLY_ACTION_PENDING = 1001 COMMAND_COMPLETED_SUCCESSFULLY_ACTION_PENDING = 1001
COMMAND_COMPLETED_SUCCESSFULLY_NO_MESSAGES = 1300 COMMAND_COMPLETED_SUCCESSFULLY_NO_MESSAGES = 1300
@ -67,6 +69,9 @@ class RegistryError(Exception):
def should_retry(self): def should_retry(self):
return self.code == ErrorCode.COMMAND_FAILED return self.code == ErrorCode.COMMAND_FAILED
def is_transport_error(self):
return self.code == ErrorCode.TRANSPORT_ERROR
# connection errors have error code of None and [Errno 99] in the err message # connection errors have error code of None and [Errno 99] in the err message
def is_connection_error(self): def is_connection_error(self):
return self.code is None return self.code is None

View file

@ -246,3 +246,7 @@ class TestConnectionPool(TestCase):
expected = "InfoDomain failed to execute due to a connection error." expected = "InfoDomain failed to execute due to a connection error."
result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True) result = registry.send(commands.InfoDomain(name="test.gov"), cleaned=True)
self.assertEqual(result, expected) self.assertEqual(result, expected)
@patch.object(EPPLibWrapper, "_test_registry_connection_success", patch_success)
def test_retries_on_transport_error(self):
"""A .send is invoked on the pool, but [description for transport error]."""