Skip to main content

rdnsresolver - Retrying DNS Resolver Package.

Project description

rdnsresolver Package Documentation

PyPI version PyPI - Python Version PyPI - License Coverage Status CI/CD Status

Overview

The rdnsresolver package provides synchronous and asynchronous DNS resolution wrappers based on dnspython. It implements automatic exponential backoff retry mechanisms utilizing tenacity for transient network failures, timeouts, and nameserver unreachability.

Class: RetryingResolver

__init__

__init__(resolver: Optional[dns.resolver.Resolver] = None, **kwargs: Any) -> None

This method initializes a synchronous DNS resolver instance with integrated retry logic.

It accepts an optional custom resolver instance, max_attempts (integer, default 5), backoff_factor (float, default 1.5), and initial_delay (float, default 1.0).

It instantiates and returns the configured RetryingResolver object.

It raises a TypeError if unsupported keyword arguments are supplied during initialization.

If no custom resolver is provided, it falls back to the global dns.resolver module functions, which share the system's underlying default DNS configuration.

resolve

resolve(qname: Union[str, dns.name.Name], rdtype: Union[int, str] = dns.rdatatype.A, **kwargs: Any) -> dns.resolver.Answer

This method executes a synchronous DNS query applying an exponential backoff strategy for transient network failures.

It requires the target qname (string or dns.name.Name), an optional rdtype (integer or string, default A), and accepts optional kwargs representing standard dnspython query parameters or temporary retry configuration overrides.

It returns a dns.resolver.Answer object containing the query results upon successful resolution.

It propagates permanent dnspython errors such as NXDOMAIN or NoAnswer immediately, and raises dns.exception.Timeout or dns.resolver.NoNameservers only after all retry attempts are exhausted.

Providing override retry parameters via kwargs modifies the behavior strictly for that specific query execution, leaving the instance's base configuration unmodified for subsequent calls.

resolve_ptr

resolve_ptr(ip_address: str, **kwargs: Any) -> dns.resolver.Answer

This method constructs a reverse DNS name from an IP address and executes a synchronous PTR record query with retry logic.

It requires the target ip_address (string) and accepts optional kwargs for standard query parameters or temporary retry overrides.

It returns a dns.resolver.Answer object containing the reverse resolution records.

It propagates permanent errors like NXDOMAIN immediately, while raising timeout or nameserver unavailability exceptions only after the retry limit is reached.

Invalid IP address strings passed to this method will immediately trigger a dns.exception.SyntaxError from the underlying reverse name constructor before any network requests are initiated.

Class: AsyncRetryingResolver

__init__

__init__(resolver: Optional[dns.asyncresolver.Resolver] = None, **kwargs: Any) -> None

This method initializes an asynchronous DNS resolver instance with integrated retry logic for non-blocking operations.

It accepts an optional custom dns.asyncresolver.Resolver instance, max_attempts (integer, default 5), backoff_factor (float, default 1.5), and initial_delay (float, default 1.0).

It instantiates and returns the configured AsyncRetryingResolver object.

It raises a TypeError if unsupported keyword arguments are supplied to the underlying constructor.

Instantiating this class outside of an active asynchronous event loop is permitted, provided that the underlying custom resolver, if supplied, does not tightly bind to an active loop during its own initialization.

resolve

async resolve(qname: Union[str, dns.name.Name], rdtype: Union[int, str] = dns.rdatatype.A, **kwargs: Any) -> dns.resolver.Answer

This method executes an asynchronous DNS query using the specified name and record type, applying the configured exponential backoff strategy for transient network exceptions.

It requires the target qname (string or dns.name.Name), an optional rdtype (integer or string, default A), and accepts optional kwargs representing standard asynchronous query parameters or temporary retry overrides.

It asynchronously yields a dns.resolver.Answer object representing the final server reply upon successful execution.

It propagates permanent dnspython errors like NXDOMAIN or NoAnswer instantly without retrying, and raises transient errors like dns.exception.Timeout or dns.resolver.NoNameservers only if the maximum retry limit is breached.

Executing this method requires an active event loop; attempting to run it synchronously or across mismatched event loops will result in an asyncio RuntimeError.

resolve_ptr

async resolve_ptr(ip_address: str, **kwargs: Any) -> dns.resolver.Answer

This method constructs a reverse DNS name from the provided IP address and executes an asynchronous PTR record query with retry logic.

It requires the target ip_address (string) and accepts optional kwargs for standard query parameters or temporary retry configuration overrides.

It asynchronously yields a dns.resolver.Answer object containing the requested reverse pointer records.

It propagates permanent errors instantly without retrying, raising timeout or nameserver unavailability exceptions solely after the maximum retry attempts are depleted.

Processing large batches of IP addresses concurrently with this method should be rate-limited by the calling application to prevent localized socket exhaustion or upstream DNS rate-limiting responses.

Global Functions

resolve

resolve(qname: Union[str, dns.name.Name], rdtype: Union[int, str] = dns.rdatatype.A, **kwargs: Any) -> dns.resolver.Answer

This function executes a synchronous DNS request utilizing a globally maintained RetryingResolver singleton instance.

It requires the target qname (string or dns.name.Name), an optional rdtype (integer or string, default A), and accepts optional kwargs for request parameters or retry configuration overrides.

It returns the dns.resolver.Answer object generated by the global singleton session.

It propagates permanent dnspython errors instantly and raises transient errors like dns.exception.Timeout or dns.resolver.NoNameservers only after all retry attempts are exhausted.

The global singleton defaults to the system's DNS configuration; if the environment dictates custom nameservers, developers must either modify the global dns.resolver.default_resolver or instantiate a dedicated RetryingResolver instead of using this function.

aresolve

async aresolve(qname: Union[str, dns.name.Name], rdtype: Union[int, str] = dns.rdatatype.A, **kwargs: Any) -> dns.resolver.Answer

This function executes an asynchronous DNS request utilizing a globally maintained AsyncRetryingResolver singleton instance.

It requires the target qname (string or dns.name.Name), an optional rdtype (integer or string, default A), and accepts optional kwargs for request parameters or retry configuration overrides.

It asynchronously yields the dns.resolver.Answer object generated by the global asynchronous singleton session.

It propagates permanent errors immediately and raises transient errors only after exhausting the configured retry limit.

The global asynchronous instance delegates to the dns.asyncresolver module; invoking this function from a distinctly different thread or a newly created event loop will trigger cross-loop execution exceptions if the underlying UDP sockets were bound elsewhere.

resolve_ptr

resolve_ptr(ip_address: str, **kwargs: Any) -> dns.resolver.Answer

This function performs a synchronous reverse DNS lookup utilizing the global RetryingResolver singleton instance.

It requires the target ip_address (string) and accepts optional kwargs for request parameters or retry configuration overrides.

It returns the dns.resolver.Answer object generated by the global singleton session.

It propagates permanent errors immediately and raises transient errors only after exhausting the configured retry limit.

Supplying non-standard IP representations may trigger parsing errors in the dns.reversename module before the global resolver instance is invoked.

aresolve_ptr

async aresolve_ptr(ip_address: str, **kwargs: Any) -> dns.resolver.Answer

This function performs an asynchronous reverse DNS lookup utilizing the global AsyncRetryingResolver singleton instance.

It requires the target ip_address (string) and accepts optional kwargs for request parameters or retry configuration overrides.

It asynchronously yields the dns.resolver.Answer object generated by the global asynchronous singleton session.

It propagates permanent errors immediately and raises transient errors only after exhausting the configured retry limit.

Similar to the synchronous variant, invalid input strings will bypass the retry mechanism entirely by failing during the local address parsing phase.

Migration Guide

Import Replacement

Projects utilizing direct dnspython implementations typically import dns.resolver and dns.asyncresolver. Migrating to this package requires importing the equivalent global functions from rdnsresolver.

The application must replace operational calls to dns.resolver and dns.asyncresolver by adding from rdnsresolver import resolve, aresolve, resolve_ptr, aresolve_ptr.

Imports for supporting modules such as dns.name, dns.rdatatype, and dns.exception remain necessary within the codebase for constructing strict query types and handling specific error structures.

Synchronous Query Migration

Existing synchronous codebase patterns execute queries using direct invocations like dns.resolver.resolve(qname, rdatatype).

The migration involves substituting dns.resolver.resolve with the resolve function.

For example, the invocation dns.resolver.resolve(current, dns.rdatatype.DS) becomes resolve(current, dns.rdatatype.DS).

The return signatures remain identical; the application will continue to receive a dns.resolver.Answer object, ensuring that downstream data processing logic requires zero modifications.

Asynchronous Query Migration

Asynchronous implementations currently rely on statements like await dns.asyncresolver.resolve(qname, rdatatype).

The migration requires replacing dns.asyncresolver.resolve with the aresolve function.

For example, the statement await dns.asyncresolver.resolve(current, dns.rdatatype.SOA) translates directly to await aresolve(current, dns.rdatatype.SOA).

The internal event loop interactions remain unchanged, but the overall execution time of the awaited function will increase dynamically if transient failures trigger the exponential backoff mechanism.

Reverse DNS (PTR) Simplification

Standard dnspython reverse lookups require a two-step process: converting the IP address string using dns.reversename.from_address(ip) and subsequently querying the resulting dns.name.Name object for a PTR record.

The rdnsresolver package provides dedicated helper functions to abstract this conversion phase and integrate the retry logic simultaneously.

A legacy code block containing rev_name = dns.reversename.from_address(ip) followed by answers = dns.resolver.resolve(rev_name, 'PTR') is replaced entirely by the single call answers = resolve_ptr(ip).

Similarly, the asynchronous equivalent answers = await dns.asyncresolver.resolve(rev_name, 'PTR') is consolidated into answers = await aresolve_ptr(ip).

Exception Handling Adjustments

Applications migrating to this package must account for changes in exception timing resulting from the introduced retry behavior.

Existing try...except blocks configured to catch dns.exception.Timeout or dns.resolver.NoNameservers will continue to function correctly.

However, these exceptions will no longer be raised immediately upon the first network failure; they will surface only after the maximum configured retry limit is exceeded.

Developers must evaluate overarching application timeouts to ensure that the cumulative delay introduced by the backoff multiplier does not violate strict internal performance boundaries or trigger secondary timeouts in higher-level services.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rdnsresolver-0.1.0.tar.gz (8.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rdnsresolver-0.1.0-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file rdnsresolver-0.1.0.tar.gz.

File metadata

  • Download URL: rdnsresolver-0.1.0.tar.gz
  • Upload date:
  • Size: 8.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for rdnsresolver-0.1.0.tar.gz
Algorithm Hash digest
SHA256 67ab8167d368496e2faea8f21340c486d0026a0a8044b56757dc347f82938644
MD5 240e65524cd95eee4aa4fd8e47b51760
BLAKE2b-256 8039ad32dcb665b033f3be1988a165d1e30890ebe9b7e22257f7e3663410b528

See more details on using hashes here.

File details

Details for the file rdnsresolver-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rdnsresolver-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for rdnsresolver-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0e2916b94271e4602269ab62d077c080458e1d006e1e475c9b26d821427a3212
MD5 0ba272ce089f0fddeb3f273c1d9e5863
BLAKE2b-256 85c9d3bdbe350c77d76609e554d424be818e5f3347d5e2bc43dd1d0ec735804f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page