Skip to main content

Stand With Ukraine

postgres-cache

Postgres Cache is a single purpose library to cover a need of a distributed cache and not willing to use Redis/Valkey/Memcached or other external caching systems.

Idea of the library is to store persisted cache in Postgres, and utilize couple of specific optimizations to make it behave comparable with other caching solutions. Local in-memory cache with invalidation via LISTEN/NOTIFY are among those optimizations.

Features

  • Pure Postgres backend – no bespoke services, just a single table plus triggers and LISTEN/NOTIFY for invalidations.

  • TTL + forced invalidation – each entry stores an optional expires_at, and clients can delete rows explicitly.

  • Dogpile protection – get_or_set uses PostgreSQL advisory locks so only one client recomputes missing items.

  • Local in-memory cache – every client keeps a bounded TTL cache that is updated/evicted via database notifications.

  • Configurable Postgres objects – notify_channel controls the LISTEN/NOTIFY channel, and schema_prefix namespaces every table/function created by the library.

  • Optional notifications – set disable_notiffy=True to skip LISTEN/NOTIFY when Postgres connection budgets are tight.

  • Load harness – runnable script that spins up many clients to assert read consistency and provide latency stats.

Usage

Install the library from PyPI:

pip install postgres-cache

PostgreSQL-backed cache

import asyncio
from postgres_cache import CacheSettings, PostgresCache

async def main():
    dsn = "postgresql://cache_user:cache_pass@localhost:5432/cache_proto"
    settings = CacheSettings(
        dsn=dsn,
        notify_channel="cache_events_marketing",
        schema_prefix="marketing_",
    )
    await PostgresCache.init_db(settings)
    async with PostgresCache(settings) as cache:
        await cache.set("profile:123", {"name": "Ava"}, ttl_seconds=300)
        user = await cache.get_or_set(
            "profile:456",
            loader=lambda: {"name": "Nova"},
            ttl_seconds=120,
        )
        print(user)

asyncio.run(main())

The clients automatically:

  • Maintain a bounded local cache.
  • Listen on notify_channel so updates/deletes on any node evict stale entries everywhere.
  • Use advisory locks on get_or_set to avoid thundering herds.

Null cache

Need a drop-in implementation that always hits the loader (for local dev or tests)?

from postgres_cache import NullCache

async with NullCache() as cache:
    await cache.set("noop", "value")  # does nothing
    assert await cache.get("noop") is None

Development setup

Python 3.11+ and uv are required for local development.

  • make tests – run the pytest suite (requires Postgres running via docker compose up).
  • make lint-and-format – format & lint code
  • make harness-load-test – launch the load harness against a local Postgres.
  • make examples-basic-usage / make examples-fastapi-api-cache – run example scripts.

Load testing

See harness/README.md for the load-test instructions and make harness-load-test helper.

Benchmarking

See benchmarks/README.md for installation steps, CLI flags, and instructions for adding more backends to the report. Note that these numbers come from an intentionally narrow, unrealistic benchmark that ignores network latency to focus purely on cache/DB interactions on the same host.

Benchmark summary

backend write mean (ms) write p95 (ms) write ops/s read mean (ms) read p95 (ms) read ops/s hit rate
postgres-cache 12.887 29.943 1023.4 1.937 5.099 10071.9 95.9%
postgres-no-local-cache 4.290 8.626 2284.4 2.274 3.600 9364.5 97.9%
postgres-no-notify 1.458 2.958 3865.2 0.208 1.624 23652.9 98.4%
valkey 0.502 0.691 4804.9 0.468 0.683 18786.0 99.1%

postgres-no-local-cache disables the client-side cache (local_max_entries=0), so the benchmark issues direct Postgres reads without invalidating values pulled from the backend. postgres-no-notify turns off LISTEN/NOTIFY fan-out (disable_notiffy=True), which means no backend invalidations occur and only the local TTL policy expires entries. Interpretation: "optimizations" implemented in this libray, does not provide any advantage.

License

Released under the MIT License.

Metadata

Release files for postgres-cache 0.1.1

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

Source distribution (sdist)

Source distribution for postgres-cache 0.1.1
File Size Uploaded Provenance
postgres_cache-0.1.1.tar.gz 16.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for postgres-cache 0.1.1
File Interpreter ABI Platform
postgres_cache-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 31.3 kB

Release files / postgres_cache-0.1.1.tar.gz

Download URL postgres_cache-0.1.1.tar.gz
Size 16.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c03393c97cc4efade71ae2da987529c65378ddc8d76b5a983c6fdb8ba5139d69
BLAKE2b-256 checksum
How to use checksums
9ce8420fae9b215e4a5293c474fdf7a29e549594e3a3d79294182511e6324766
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 16, 2025.

Transparency log

Release files / postgres_cache-0.1.1-py3-none-any.whl

Download URL postgres_cache-0.1.1-py3-none-any.whl
Size 15.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ee50d6589d523fd849dab9623d6b72701ae2446b81c540b1bd61b49f1fdc3b17
BLAKE2b-256 checksum
How to use checksums
4d72cdea20ca22b07e475032192f9af9cc647e9b8adaee8a4b34c9baa2d8a79d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 16, 2025.

Transparency log

Security for postgres-cache 0.1.1

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for postgres_cache-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 16, 2025.

Transparency log

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.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

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