← Back to all articles

Engineering

Resume multi-model work without paying for successful steps again

A bounded fan-out collector and durable lease design.

AI-generated editorial illustration.

1. Save each valid provider result independently

A comparison with several providers should not be one all-or-nothing cache write. Validate and save a successful provider evaluation as soon as it is available. If another provider times out, a retry can reuse the completed evaluations. Give each unit a deterministic key that includes product facts, model and rubric. A complete panel report can still require every configured seat, but its failure should not erase successful intermediate work. A partial panel, when shown, must state which providers are missing.

2. Collect successes and errors separately

The example simulates three providers, with one temporary failure. It stores successful steps and retries only the failed provider on the second run. A thread pool limits fan-out; it does not establish cross-instance ownership or cancel an external request automatically. Configure actual socket/provider deadlines inside the worker. Calling Future.result with a timeout only limits how long that caller waits; it is not a substitute for a network timeout or a provider cancellation mechanism.

from concurrent.futures import ThreadPoolExecutor, as_completed
cache, calls = {}, []

def collect(providers, worker):
    errors = {}
    todo = [p for p in providers if p not in cache]
    with ThreadPoolExecutor(max_workers=3) as pool:
        futures = {pool.submit(worker,p):p for p in todo}
        for future in as_completed(futures):
            provider = futures[future]
            try:
                result = future.result()
                if not isinstance(result,dict) or 'score' not in result:
                    raise ValueError('invalid result')
                cache[provider] = result
            except (TimeoutError, ValueError) as error:
                errors[provider] = type(error).__name__
    return errors

def first(p):
    calls.append(p)
    if p == 'B': raise TimeoutError('temporary')
    return {'score':80}

assert collect(['A','B','C'], first) == {'B':'TimeoutError'}
calls.clear()
def retry(p):
    calls.append(p)
    return {'score':81}
assert collect(['A','B','C'], retry) == {}
assert calls == ['B']
print('only the unfinished provider was retried')

3. Add a durable work lease

An in-process mutex disappears on restart and does not coordinate multiple Cloud Run instances. Store a lease with a work key, random owner and expiry. Claim or renew ownership transactionally, and release only when the owner matches. Set expiry longer than the bounded work duration or implement renewal with failure handling. When a lease expires, recheck the result cache before starting again. Two workers can still overlap around failure boundaries, so external operations that support idempotency should use a stable key as well.

4. Retry only recoverable failures

Separate an invalid credential or unsupported model from a temporary timeout or rate limit. Use a finite retry count and jittered backoff, and respect a provider retry hint when available. Every attempted model request should consume an application budget even if it fails. Show real provider status to the user instead of an invented percentage. The goal is to resume a decision with minimal duplicated work; an endless spinner that repeatedly launches the same calls is neither reliability nor a good experience.

Compare your options →Explore GEO ↗

All product names, logos and brands belong to their respective owners and are used for identification only. VersusSmart is an independent service and is not affiliated with, sponsored by or endorsed by these providers.