Accumulate items, process as batch. Efficiency & throughput.
import asyncio
from typing import List, Callable
class Batcher:
def __init__(self, batch_size: int, timeout: float, process_fn: Callable):
self.batch_size = batch_size
self.timeout = timeout
self.process_fn = process_fn
self.items = []
self.lock = asyncio.Lock()
async def add_item(self, item):
"""Add an item, trigger batch processing if needed."""
async with self.lock:
self.items.append(item)
if len(self.items) >= self.batch_size:
await self._flush()
async def _flush(self):
"""Process accumulated items as a batch."""
if not self.items:
return
batch = self.items[:]
self.items = []
await self.process_fn(batch)
async def background_flusher(self):
"""Periodically flush if timeout expires."""
while True:
await asyncio.sleep(self.timeout)
async with self.lock:
await self._flush()
# Usage
async def process_batch(items: List[int]):
print(f"Processing batch of {len(items)}: {items}")
# Bulk insert to database
await asyncio.sleep(0.1) # Simulate DB operation
async def main():
batcher = Batcher(batch_size=100, timeout=1.0, process_fn=process_batch)
# Start background flusher
flush_task = asyncio.create_task(batcher.background_flusher())
# Send 250 items over time
for i in range(250):
await batcher.add_item(i)
await asyncio.sleep(0.01)
# Final flush
async with batcher.lock:
await batcher._flush()
flush_task.cancel()
asyncio.run(main())
from fastapi import FastAPI
app = FastAPI()
user_batcher = Batcher(batch_size=100, timeout=1.0, process_fn=insert_users_to_db)
@app.post("/users/batch")
async def create_user(user_data: dict):
await user_batcher.add_item(user_data)
return {"status": "queued"}
@app.on_event("shutdown")
async def on_shutdown():
# Flush remaining items on shutdown
async with user_batcher.lock:
await user_batcher._flush()