Skip to content

ConnectionResetError won't be identified as retryable #1344

@akhenakh

Description

@akhenakh

Some of our tests are failing with:

query_and_describe attempt 1 from PID 8 to GET /versions/us.shared_airspace failed with non-retryable ConnectionError: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))

#1310 is trying to fix an issue to catch ConnectionResetError so they can be retried.
But it seems it will miss this error anyway, it needs to also traverse exception.args - to find exceptions wrapped as constructor arguments, not just exceptions in the chain:

from http.client import RemoteDisconnected

def context_contains(exception, types) -> bool:
    if exception.__class__ in types:
        return True
    parent = getattr(exception, '__context__', None)
    if parent:
        return context_contains(parent, types)
    else:
        return False
# Simulate the actual error our the logs
inner = ConnectionResetError(104, 'Connection reset by peer')
e = ConnectionError('Connection aborted.', inner)
print(f'e.__context__: {e.__context__}')
print(f'e.args: {e.args}')
print(f'Retryable with code: {context_contains(e, (RemoteDisconnected, ConnectionResetError))}')

e.context: None
e.args: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Retryable with code: False

The ConnectionResetError is in args, not context.

from http.client import RemoteDisconnected

def context_contains_fixed(exception, types) -> bool:
    if exception.__class__ in types:
        return True
    parent = getattr(exception, '__context__', None)
    if parent:
        if context_contains_fixed(parent, types):
            return True
    # Also check args for wrapped exceptions
    for arg in getattr(exception, 'args', []):
        if isinstance(arg, BaseException):
            if context_contains_fixed(arg, types):
                return True
    return False
inner = ConnectionResetError(104, 'Connection reset by peer')
e = ConnectionError('Connection aborted.', inner)
print(f'e.__context__: {e.__context__}')
print(f'e.args: {e.args}')
print(f'Retryable with code: {context_contains_fixed(e, (RemoteDisconnected, ConnectionResetError))}')

e.context: None
e.args: ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))
Retryable with code: True

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priorityautomated-testingRelated to automated testing toolsbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions