Skip to main content

refresh-engine

PyPI Python CI Documentation License

Keep anything in sync with its source by refreshing only what changed.

refresh-engine is an asyncio-first, domain-neutral Python library for keeping derived data current: search indexes, caches, embeddings, configuration, registries, or anything else built from a source. You describe how to list and read resources and how to apply a change; the engine detects what changed, plans the work in dependency order, runs it safely, and remembers the outcome.

Discover, observe, detect changes, plan, execute, and persist

Features

  • Precise change detection. Deterministic fingerprints detect added, modified, and deleted resources. Reliable cheap indicators, such as ETags or version tokens, skip reading unchanged resources entirely.
  • Four refresh modes. Incremental, full, dependency-aware, and targeted refreshes, with targets chosen by ID or by composable selectors.
  • Dependency ordering. Dependencies are refreshed before their dependents, changes propagate to everything that depends on them, and cycles are isolated.
  • Safe by default. Bounded concurrency, retries with jittered exponential backoff, timeouts, and fail-fast or best-effort policies. A partial discovery never deletes anything, and failed work is retried by the next refresh.
  • Durable state. State advances only for successful resources, in one atomic commit per refresh. Use the in-memory store or plug in your own database.
  • Scheduling and overlap control. A drift-free interval scheduler and policies that coalesce, queue, skip, or supersede overlapping requests.
  • Observability. Typed lifecycle events with correlation IDs, structured logging through structlog with secret redaction, metrics, and optional OpenTelemetry spans and metrics using application-owned providers.
  • Lightweight and typed. Fully type-annotated, with two runtime dependencies: structlog and tenacity.

Installation

refresh-engine requires Python 3.12 or newer.

pip install refresh-engine

For the optional OpenTelemetry integration, install refresh-engine[otel].

Quick start

Implement a source that lists and reads resources, and an operation that applies each change. The engine does the rest:

import asyncio

from refresh_engine import (
    DiscoveryResult,
    PlanAction,
    RefreshEngine,
    ResourceSource,
    RefreshRequest,
    Resource,
    ResourceSnapshot,
)

CATALOG = {"apples": 120, "pears": 80}
SEARCH_INDEX: dict[str, int] = {}


class InventorySource(ResourceSource):
    async def discover(self) -> DiscoveryResult:
        return DiscoveryResult(Resource(item) for item in sorted(CATALOG))

    async def snapshot(self, resource: Resource, /) -> ResourceSnapshot:
        return ResourceSnapshot(
            resource.resource_id, content=CATALOG[resource.resource_id]
        )


async def update_index(
    resource: Resource,
    snapshot: ResourceSnapshot | None,
    action: PlanAction,
    request: RefreshRequest,
    /,
) -> None:
    if action is PlanAction.DELETE:
        SEARCH_INDEX.pop(resource.resource_id, None)
    elif snapshot is not None:
        SEARCH_INDEX[resource.resource_id] = snapshot.content


async def main() -> None:
    async with RefreshEngine(InventorySource(), update_index) as engine:
        first = await engine.refresh()
        print(f"{first.status}: refreshed {first.refreshed_count}", SEARCH_INDEX)

        CATALOG["pears"] = 75
        del CATALOG["apples"]
        second = await engine.refresh()
        print(
            f"{second.status}: modified {second.modified_count},"
            f" deleted {second.deleted_count}",
            SEARCH_INDEX,
        )


asyncio.run(main())
success: refreshed 2 {'apples': 120, 'pears': 80}
success: modified 1, deleted 1 {'pears': 75}

The second refresh touches only the modified and the deleted resource. Continue with the getting started guide to add durable state, dependencies, scheduling, and logging.

Performance

The engine's overhead is small next to real I/O: with in-memory sources, a full refresh of 100,000 resources takes about 3 seconds, and an incremental refresh that finds nothing changed takes about half a second. See the benchmarks for the method and details.

Documentation

The documentation covers:

Agent Skills

Coding agents such as Claude Code, Codex, Cursor, and GitHub Copilot can use the refresh-engine Agent Skill to integrate the library correctly:

npx skills add https://github.com/smuniharish/refresh-engine/tree/master/refresh-engine-skills/skills/refresh-engine

Contributing

Contributions are welcome. Read the contributing guide, and report vulnerabilities as described in the security policy. Notable changes are listed in the changelog.

License

refresh-engine is licensed under the Apache License 2.0.

Metadata

Release files for refresh-engine 1.0.0

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

Source distribution (sdist)

Source distribution for refresh-engine 1.0.0
File Size Uploaded Provenance Actions
refresh_engine-1.0.0.tar.gz 56.4 kB Without provenance Details for refresh_engine-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for refresh-engine 1.0.0
File Interpreter ABI Platform Actions
refresh_engine-1.0.0-py3-none-any.whl Python 3 none any Details for refresh_engine-1.0.0-py3-none-any.whl

Total release size: 119.6 kB

Release files / refresh_engine-1.0.0.tar.gz

Download URL refresh_engine-1.0.0.tar.gz
Size 56.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ea427a1036a404f83b3d7125bba3305cbc8defd130e9aa4d1daa403c02d377f7
BLAKE2b-256 checksum
How to use checksums
05a97ec46483dafd13c0c056b776ae3d9ce604bfac8601fdef7ca7ccca8c2702
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / refresh_engine-1.0.0-py3-none-any.whl

Download URL refresh_engine-1.0.0-py3-none-any.whl
Size 63.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a6ab77e7f6c1f20fe87512fe2ead203dbf995a781f0136feb3f13b3c6f6f183
BLAKE2b-256 checksum
How to use checksums
dc7d5d5bdf13a02988c8d4aa006b3bfd2a1e7cd360befe35a55e70410f4bf58f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for refresh-engine 1.0.0

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