Skip to main content

db-try

A Python library providing robust retry mechanisms, connection utilities, and transaction helpers for PostgreSQL and SQLAlchemy applications.

Features

  • Retry Decorators: Automatic retry logic for transient database errors
  • Connection Factories: Robust connection handling with multi-host support
  • DSN Utilities: Flexible Data Source Name parsing and manipulation
  • Transaction Helpers: Simplified transaction management with automatic cleanup

Installation

Using uv

uv add db-try

Using pip

pip install db-try

ORM-Based Usage Examples

1. Database Operations with Automatic Retry

Protect your database operations from transient failures using ORM models:

import asyncio
import sqlalchemy as sa
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from db_try import postgres_retry

class User(DeclarativeBase):
    __tablename__ = "users"
    
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(sa.String())
    email: Mapped[str] = mapped_column(sa.String(), index=True)

# Apply retry logic to ORM operations
@postgres_retry
async def get_user_by_email(session: AsyncSession, email: str) -> User:
    return await session.scalar(
        sa.select(User).where(User.email == email)
    )


async def main():
    engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/mydb")
    async with AsyncSession(engine) as session:
        # Automatically retries on connection failures or serialization errors
        user = await get_user_by_email(session, "john.doe@example.com")
        if user:
            print(f"Found user: {user.name}")

asyncio.run(main())

2. High Availability Database Connections

Set up resilient database connections with multiple fallback hosts:

import sqlalchemy as sa
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from db_try import build_connection_factory, build_db_dsn


# Configure multiple database hosts for high availability
multi_host_dsn = (
    "postgresql://user:password@/"
    "myapp_db?"
    "host=primary-db:5432&"
    "host=secondary-db:5432&"
    "host=backup-db:5432"
)

# Build production-ready DSN
dsn = build_db_dsn(
    db_dsn=multi_host_dsn,
    database_name="production_database",
    drivername="postgresql+asyncpg"
)

# Create connection factory with timeout
connection_factory = build_connection_factory(
    url=dsn, 
    timeout=5.0  # 5 second connection timeout
)

# Engine will automatically try different hosts on failure
engine = create_async_engine(dsn, async_creator=connection_factory)

3. Simplified Transaction Management

Handle database transactions with automatic cleanup using ORM:

import dataclasses
import datetime
import typing

from schemas import AnalyticsEventCreate, AnalyticsEvent
from db_try import Transaction, postgres_retry

from your_service_name.database.tables import EventsTable
from your_service_name.producers.analytics_service_events_producer import AnalyticsEventsProducer
from your_service_name.repositories.events_repository import EventsRepository
from your_service_name.settings import settings


@dataclasses.dataclass(kw_only=True, frozen=True, slots=True)
class CreateEventUseCase:
    events_repository: EventsRepository
    transaction: Transaction
    analytics_events_producer: AnalyticsEventsProducer

    @postgres_retry
    async def __call__(
        self,
        event_create_data: AnalyticsEventCreate,
    ) -> AnalyticsEvent:
        async with self.transaction:
            model: typing.Final = EventsTable(
                **event_create_data.model_dump(),
                created_at=datetime.datetime.now(tz=settings.common.default_timezone),
            )
            saved_event: typing.Final[EventsTable] = await self.events_repository.create(model)
            event: typing.Final = AnalyticsEvent.model_validate(saved_event)
            await self.analytics_events_producer.send_message(event)
            await self.transaction.commit()
            return event

4. Serializable Transactions for Consistency

Use serializable isolation level to prevent race conditions with ORM:

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from db_try import Transaction


async def main():
    engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/mydb")
    
    async with AsyncSession(engine) as session:
        strict_transaction = Transaction(
            session=session,
            isolation_level="SERIALIZABLE",
        )
        # use strict_transaction where needed

Configuration

The library can be configured using environment variables:

Variable Description Default
DB_TRY_RETRIES_NUMBER Number of retry attempts for database operations 3

Example:

export DB_UTILS_RETRIES_NUMBER=5

API Reference

Retry Decorator

  • @postgres_retry - Decorator for async functions that should retry on database errors

Connection Utilities

  • build_connection_factory(url, timeout) - Creates a connection factory for multi-host setups
  • build_db_dsn(db_dsn, database_name, use_replica=False, drivername="postgresql") - Builds a DSN with specified parameters
  • is_dsn_multihost(db_dsn) - Checks if a DSN contains multiple hosts

Transaction Helper

  • Transaction(session, isolation_level=None) - Context manager for simplified transaction handling

Requirements

  • Python 3.13+
  • SQLAlchemy with asyncio support
  • asyncpg PostgreSQL driver
  • tenacity for retry logic

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for db-try 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for db-try 0.2.2
File Size Uploaded Provenance Actions
db_try-0.2.2.tar.gz 5.6 kB Without provenance Details for db_try-0.2.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for db-try 0.2.2
File Interpreter ABI Platform Actions
db_try-0.2.2-py3-none-any.whl Python 3 none any Details for db_try-0.2.2-py3-none-any.whl

Total release size: 12.7 kB

Release files / db_try-0.2.2.tar.gz

Download URL db_try-0.2.2.tar.gz
Size 5.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a8a24ac5d77fd73330af7608ce451141e10544ee186b2f84c8a9caaed8e4552a
BLAKE2b-256 checksum
How to use checksums
33f647fae9d379cd4b340c8a7fefc5ac4cc2dd794cec24d3fb8670b05953eb90
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / db_try-0.2.2-py3-none-any.whl

Download URL db_try-0.2.2-py3-none-any.whl
Size 7.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b6b9b835e20609bf8cfdb7933bdfb0b945b1ab86e26e13af7c383095fe6f0d9b
BLAKE2b-256 checksum
How to use checksums
83b1e4d7c2a32aadb2c8dadae422f945b2f9bd67e0b09ceae1fa90854b348885
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.9 {"installer":{"name":"uv","version":"0.9.9"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for db-try 0.2.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page