Skip to main content

Transparent temporal coalescing and inline micro-batching for Python.

Project description

concresce 💧

Transparent temporal coalescing and inline micro-batching.

Standard solutions to N+1 database or network bottlenecks require spinning up external message queues, background workers, or complex task graphs. concresce solves this dynamically. You write the function as if it processes a single item, and the runtime transparently merges concurrent calls into a single batch in the background.

uv add concresce

The Difference

Concept Standard Async Loop Message Queues (Celery/Kafka) concresce
Network Footprint N requests for N items. 1 request for N items. 1 request for N items.
Architectural Overhead None. High (Requires external broker). None (Pure inline code).
Return Routing Native variables. Complex (Webhooks / Polling). Native variables (Futures resolve).

Usage

You need exactly two primitives: @batch to define the barrier constraint, and collect() to suspend the execution and pool data.

By default there is zero configuration: the batch window is dynamically defined by the event loop's microtask queue, and routing is handled natively by your return types. A single optional window knob is available when you need a wider collection window.

import asyncio
from concresce import batch, collect

@batch
async def fetch_user_score(user_id):
    # 1. Execution pauses here.
    # Concurrent calls inside the current event loop tick pool their `user_id`s.
    batch_ids = await collect(user_id)

    # 2. Only ONE execution path (the leader) resumes from this point.
    # The others remain safely suspended via Exception-driven control flow.
    print(f"Making 1 network call for {len(batch_ids)} users...")
    bulk_results = await db.bulk_fetch_scores(batch_ids)

    # 3. The leader returns the raw bulk list or dictionary.
    # The decorator natively maps and distributes the results back to the followers.
    return bulk_results


async def main():
    # Fire off 5 requests simultaneously
    results = await asyncio.gather(
        fetch_user_score(1),
        fetch_user_score(2),
        fetch_user_score(3),
        fetch_user_score(4),
        fetch_user_score(5)
    )

    # Returns:[100, 250, 190, 300, 120]
    print(results)

asyncio.run(main())

The window parameter

By default a batch spans a single event-loop tick: the leader yields once (await asyncio.sleep(0)) and then processes whatever pooled during that tick. That is ideal under load, but on bursty traffic the items you want to coalesce can land a few milliseconds apart, in separate ticks.

Pass a window to @batch to widen the collection window. It is a datetime.timedelta that decides how long the leader sleeps before it collects and runs the batch — every call that arrives during that window joins the same batch.

from datetime import timedelta
from concresce import batch, collect

@batch(window=timedelta(milliseconds=5))
async def fetch_user_score(user_id):
    batch_ids = await collect(user_id)
    return await db.bulk_fetch_scores(batch_ids)
  • @batch (bare) — leader sleeps 0; the batch is one event-loop tick. This is the default.
  • @batch(window=timedelta(milliseconds=5)) — leader sleeps 5 ms; everything that arrives in that window is coalesced.

Widening the window trades a little latency for larger, more efficient batches.

Core Mechanics

  • Event Loop Batching: With the default zero-length window (timedelta(0)) concresce yields exactly once to the event loop. Under heavy load, batches are large; under low load, they execute instantly. A wider window simply extends how long the leader waits before collecting.
  • Native Type Routing: The leader does not call a special scatter function. If it returns a list or tuple, the system unzips it by index. If it returns out-of-order or missing data, return a dictionary ({id: result}) and concresce routes by key. Any other return type — or a sequence whose length does not match the number of callers — raises BatchRoutingError for every caller instead of hanging.
  • Fault Propagation: If the leader crashes during processing, the exception is intercepted and replicated to all suspended followers. Nobody hangs, and the stack unwinds naturally.

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

concresce-5.0.0.tar.gz (4.8 kB view details)

Uploaded Source

Built Distribution

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

concresce-5.0.0-py3-none-any.whl (5.6 kB view details)

Uploaded Python 3

File details

Details for the file concresce-5.0.0.tar.gz.

File metadata

  • Download URL: concresce-5.0.0.tar.gz
  • Upload date:
  • Size: 4.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for concresce-5.0.0.tar.gz
Algorithm Hash digest
SHA256 65c87bfcae41c7436b590f8feb3e73149a226fb8be858a850f0c8149c30b33eb
MD5 df33e26a136e97b00fa4f61cfe570595
BLAKE2b-256 4f8a4785252ad49cdeb31b65a482a5251fa50608182b2fbb5bbbe288aa21ee40

See more details on using hashes here.

File details

Details for the file concresce-5.0.0-py3-none-any.whl.

File metadata

  • Download URL: concresce-5.0.0-py3-none-any.whl
  • Upload date:
  • Size: 5.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for concresce-5.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17f9ef95bed6dfadb9d74373d5fef9d4c931148219d6ea0486b3f3a0d8a6d3b5
MD5 d61fab7ddba3ccce48f5e108f6cc9a85
BLAKE2b-256 b295eba5d0c4b3c1038b9f48fb4b46018f4bd2a0162e7edc4668689b479d9816

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