async-programming
Asynchronous programming patterns and best practices
Source facts
- Repository
- ffsshhttiikk/opencode-agents-skills
- Last source activity
- February 28, 2026 at 22:46
- Detected SKILL.md language
- English
- Stars
- 3
- Forks
- 2
Install options
The review-first prompt is selected by default. You can switch to a direct command or download a local copy.
Review the source files
Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.
Showing SKILL.md
SKILL.md
Source instructions · Read-only preview- name
- async-programming
- description
- Asynchronous programming patterns and best practices
- license
- MIT
- compatibility
- opencode
- metadata
- {"audience":"developers","category":"programming"}
## What I do
- Write async/await code in Python and JavaScript
- Implement concurrent operations
- Handle async errors properly
- Use thread pools and process pools
- Implement producer-consumer patterns
- Manage async resources with context managers
- Handle backpressure and rate limiting
- Debug async code
## When to use me
When implementing asynchronous operations or concurrency patterns.
## Python Asyncio
```python
import asyncio
import aiohttp
from typing import List, Optional
from dataclasses import dataclass
from contextlib import asynccontextmanager
@dataclass
class FetchResult:
url: str
status: int
content: str
duration_ms: float
class AsyncFetcher:
"""Concurrent HTTP fetcher with rate limiting."""
def __init__(
self,
max_concurrent: int = 10,
max_per_second: float = 5.0
) -> None:
self.semaphore = asyncio.Semaphore(max_concurrent)
self.rate_limiter = AsyncRateLimiter(max_per_second)
self.results: List[FetchResult] = []
async def fetch(
self,
session: aiohttp.ClientSession,
url: str,
timeout: int = 10
) -> FetchResult:
"""Fetch a single URL with rate limiting."""
async with self.semaphore:
async with self.rate_limiter:
start = asyncio.get_event_loop().time()
try:
async with session.get(
url,
timeout=aiohttp.ClientTimeout(total=timeout)
) as response:
content = await response.text()
duration = (asyncio.get_event_loop().time() - start) * 1000
return FetchResult(
url=url,
status=response.status,
content=content,
duration_ms=duration,
)
except Exception as e:
return FetchResult(
url=url,
status=0,
content=str(e),
duration_ms=0,
)
async def fetch_all(
self,
urls: List[str],
progress_callback: Optional[callable] = None
) -> List[FetchResult]:
"""Fetch multiple URLs concurrently."""
async with aiohttp.ClientSession() as session:
tasks = [self.fetch(session, url) for url in urls]
results = []
for i, coro in enumerate(asyncio.as_completed(tasks)):
result = await coro
results.append(result)
if progress_callback:
progress_callback(i + 1, len(urls))
return results
class AsyncRateLimiter:
"""Token bucket rate limiter for async operations."""
def __init__(
self,
rate: float, # tokens per second
capacity: Optional[int] = None
) -> None:
self.rate = rate
self.capacity = capacity or int(rate)
self.tokens = self.capacity
self.last_update = asyncio.get_event_loop().time()
self.lock = asyncio.Lock()
async def acquire(self, tokens: int = 1) -> float:
"""Acquire tokens, wait if necessary. Returns wait time."""
async with self.lock:
now = asyncio.get_event_loop().time()
elapsed = now - self.last_update
# Add tokens based on elapsed time
new_tokens = elapsed * self.rate
self.tokens = min(self.capacity, self.tokens + new_tokens)
self.last_update = now
# Wait for tokens if needed
if self.tokens >= tokens:
self.tokens -= tokens
return 0.0
# Calculate wait time
needed = tokens - self.tokens
wait_time = needed / self.rate
self.tokens = 0
self.last_update = now + wait_time
return wait_time
async def __aenter__(self) -> 'AsyncRateLimiter':
await self.acquire()
return self
async def __aexit__(self, *args) -> None:
pass
@asynccontextmanager
async def async_timer(name: str):
"""Context manager for timing async operations."""
start = asyncio.get_event_loop().time()
try:
yield
finally:
duration = (asyncio.get_event_loop().time() - start) * 1000
print(f"{name}: {duration:.2f}ms")
```
## Concurrent Processing
```python
import asyncio
from concurrent.futures import ThreadPoolExecutor
from typing import List, TypeVar, Callable, Awaitable
T = TypeVar('T')
R = TypeVar('R')
class ConcurrentProcessor:
"""Process items with configurable concurrency."""
def __init__(
self,
max_workers: int = 10,
use_processes: bool = False
) -> None:
self.max_workers = max_workers
self.executor = None
self.use_processes = use_processes
def __enter__(self) -> 'ConcurrentProcessor':
if self.use_processes:
self.executor = ProcessPoolExecutor(max_workers=self.max_workers)
else:
self.executor = ThreadPoolExecutor(max_workers=self.max_workers)
return self
def __exit__(self, *args) -> None:
self.executor.shutdown(wait=True)
async def map(
self,
func: Callable[[T], R],
items: List[T],
progress_callback: Optional[Callable[[int], None]] = None
) -> List[R]:
"""Map function over items concurrently."""
loop = asyncio.get_event_loop()
tasks = []
for item in items:
task = loop.run_in_executor(
self.executor,
func,
item
)
tasks.append(task)
results = []
for i, future in enumerate(asyncio.as_completed(tasks)):
result = await future
results.append(result)
if progress_callback:
progress_callback(i + 1)
return results
async def map_ordered(
self,
func: Callable[[T], Awaitable[R]],
items: List[T]
) -> List[R]:
"""Map async function preserving order."""
tasks = [func(item) for item in items]
return await asyncio.gather(*tasks)
class ProducerConsumer:
"""Producer-consumer pattern with bounded queue."""
def __init__(
self,
max_queue_size: int = 100,
max_workers: int = 5
) -> None:
self.queue = asyncio.Queue(max_queue_size)
self.workers = max_workers
self.running = True
async def producer(self, items: List[T]) -> None:
"""Produce items for consumption."""
for item in items:
await self.queue.put(item)
# Signal completion
for _ in range(self.workers):
await self.queue.put(None)
async def consumer(self, func: Callable[[T], Awaitable[R]]) -> List[R]:
"""Consume items and process them."""
results = []
while self.running:
item = await self.queue.get()
if item is None:
self.queue.task_done()
break
try:
result = await func(item)
results.append(result)
except Exception as e:
print(f"Error processing item: {e}")
finally:
self.queue.task_done()
return results
async def run(
self,
items: List[T],
func: Callable[[T], Awaitable[R]],
progress_callback: Optional[Callable[[int], None]] = None
) -> List[R]:
"""Run the producer-consumer pipeline."""
results = []
async def worker():
while True:
item = await self.queue.get()
if item is None:
break
try:
result = await func(item)
results.append(result)
finally:
self.queue.task_done()
# Start workers
workers = [worker() for _ in range(self.workers)]
# Start producer
producer_task = asyncio.create_task(self.producer(items))
# Wait for all
await asyncio.gather(producer_task, *workers)
return results
```
## Error Handling
```python
import asyncio
from typing import Optional, TypeVar, Callable
from dataclasses import dataclass
@dataclass
class AsyncResult:
success: bool
value: Optional[R] = None
error: Optional[Exception] = None
duration_ms: float = 0
class AsyncErrorHandler:
"""Handle errors in async code with retries."""
def __init__(
self,
max_retries: int = 3,
backoff_factor: float = 1.0,
exceptions: tuple = (Exception,)
) -> None:
self.max_retries = max_retries
self.backoff_factor = backoff_factor
self.exceptions = exceptions
async def execute(
self,
func: Callable[..., Awaitable[R]],
*args,
**kwargs
) -> AsyncResult[R]:
"""Execute with retry logic."""
start = asyncio.get_event_loop().time()
for attempt in range(self.max_retries + 1):
try:
result = await func(*args, **kwargs)
duration = (asyncio.get_event_loop().time() - start) * 1000
return AsyncResult(
success=True,
value=result,
duration_ms=duration,
)
except self.exceptions as e:
if attempt == self.max_retries:
duration = (asyncio.get_event_loop().time() - start) * 1000
return AsyncResult(
success=False,
error=e,
duration_ms=duration,
)
delay = self.backoff_factor * (2 ** attempt)
await asyncio.sleep(delay)
duration = (asyncio.get_event_loop().time() - start) * 1000
return AsyncResult(success=False, duration_ms=duration)
class TimeoutHandler:
"""Handle async operations with timeouts."""
async def with_timeout(
self,
coro: Awaitable[R],
timeout: float,
fallback: Optional[Callable[[], R]] = None
) -> R:
"""Execute with timeout."""
try:
return await asyncio.wait_for(coro, timeout=timeout)
except asyncio.TimeoutError:
if fallback:
return fallback()
raise TimeoutError(f"Operation timed out after {timeout}s")
async def with_individual_timeout(
self,
tasks: List[asyncio.Task],
timeout: float
) -> List[Optional[R]]:
"""Wait for tasks with individual timeouts."""
results = [None] * len(tasks)
for i, task in enumerate(tasks):
try:
results[i] = await asyncio.wait_for(task, timeout=timeout)
except asyncio.TimeoutError:
results[i] = None
except Exception:
results[i] = None
return results
```
## JavaScript Async
```typescript
// Promise utilities
class AsyncUtils {
static async withTimeout<T>(
promise: Promise<T>,
timeoutMs: number,
fallback?: T
): Promise<T> {
return Promise.race([
promise,
new Promise<T>((_, reject) =>
setTimeout(() => {
if (fallback !== undefined) {
resolve(fallback);
} else {
reject(new Error(`Timeout after ${timeoutMs}ms`));
}
}, timeoutMs)
),
]);
}
static async retry<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
delayMs: number = 1000
): Promise<T> {
let lastError: Error | null = null;
for (let i = 0; i <= maxRetries; i++) {
try {
return await fn();
} catch (e) {
lastError = e as Error;
if (i < maxRetries) {
await new Promise(resolve => setTimeout(resolve, delayMs * (i + 1)));
}
}
}
throw lastError;
}
static async allSettled<T>(
promises: Promise<T>[]
): Promise<{ status: 'fulfilled' | 'rejected'; value?: T; reason?: Error }[]> {
return Promise.all(
promises.map(promise =>
promise
.then(value => ({ status: 'fulfilled' as const, value }))
.catch(reason => ({ status: 'rejected' as const, reason }))
)
);
}
static async mapWithLimit<T, R>(
items: T[],
concurrency: number,
fn: (item: T) => Promise<R>
): Promise<R[]> {
const results: R[] = [];
const executing: Promise<void>[] = [];
for (const item of items) {
const promise = Promise.resolve().then(() => fn(item));
results.push(promise);
executing.push(promise);
if (executing.length >= concurrency) {
await Promise.race(executing);
const completed = executing.findIndex(p => p === promise);
if (completed > -1) {
executing.splice(completed, 1);
}
}
}
return Promise.all(results);
}
}
```
View on GitHub