LAB429/ Cheetah product page ↗

Cheetah / Cheetah documentation

Matching and selection

Worker choice has two different stages. Eligibility removes clients and contexts that cannot run the task. Selection chooses one candidate from what remains. Keep hard requirements in the first stage; a preference or scoring strategy is not a substitute for a correctness boundary.

Eligibility begins with live presence

Every acquisition reads IConnectionRegistry.get_presence(user_id). A context is selectable only when its client appears in that heartbeat-backed presence view. An old state report by itself is not enough.

The manager then applies these filters:

  1. requirements compares exact top-level key/value pairs with each connection's client_metadata;
  2. client_type limits contexts to browser, console, mobile, or web;
  3. the context must be worker-owned, unassigned, and active or idle;
  4. browser placement can add window and capacity conditions.

Requirement matching is deliberately small. It is exact equality, not a nested query language, range expression, or capability implication system. A request such as {"region": "eu", "account": "billing"} requires both fields to be present with those exact values.

Connection metadata is useful only to the degree that the product controls its source. Do not put a security decision in self-asserted client metadata unless authentication or admission policy already established that the client may make that assertion.

Affinity is a preference

affinity_client_id tries one connected eligible client first. If it has no assignable worker, the manager can choose another eligible client. Use affinity for cache locality, continuity, or performance where fallback is acceptable.

Use a hard metadata requirement or a product-owned selection boundary when fallback would be incorrect. In particular, affinity does not turn a client ID into an authorization rule.

Choose a strategy for a measurable objective

The optional dispatch strategy sees only the idle candidates that passed eligibility.

StrategySelection ruleImportant limit
no explicit strategyasks eligible clients for an assignable workerno fairness or stable global ordering promise
RoundRobinStrategycycles through candidates sorted by client and context IDcounter is in one manager process and per user
LeastBusyStrategyprefers the client with the fewest currently assigned workersmeasures registry assignments, not CPU, page cost, or a durable queue
ScoringStrategychooses the highest application-supplied numeric scorescorer owns meaning, tie behavior, and exceptions
CompositeStrategyuses the first strategy in the chain that returns a candidatecombines fallbacks, not scores; all None means no existing worker was selected

For example, a single-process application can request round-robin selection without changing the pool contract:

from servercheetah.services import RoundRobinStrategy, WorkerContextManager

wcm = WorkerContextManager(
    context_registry=context_registry,
    connection_registry=connection_registry,
    app_node=app_node,
    dispatch_strategy=RoundRobinStrategy(),
)

Do not infer distributed fairness from these strategies. Several manager processes maintain separate counters and can observe different snapshots. When scheduling order, quotas, or priority are product invariants, keep them in an application-owned coordinator and use WCM for the final live-context assignment.

Atomic assignment settles races

Querying and strategy selection do not reserve a worker. The manager calls assign_task(user_id, client_id, context_id, task_id) after selection. If another caller won the candidate, the registry returns False; the manager removes that context and asks the strategy to choose from the remaining candidates.

This retry protects against ordinary selection races. The concrete registry controls the scope of atomicity: in-memory registries coordinate one process, while Redis registries use shared mutation primitives for several processes. Neither turns the product task into a distributed transaction.

Auto-provision only after selection fails

When no existing candidate is assigned and auto_provision=True, the manager may create a context on an eligible connected client. Current generic provisioning supports browser and console clients. Mobile and web contexts can participate when already reported as workers, but the manager does not know how to create them.

Browser creation has additional placement and capacity rules documented in Browser placement and protection. Console creation sends create_flow(worker=True), waits for the flow to appear in the context registry, and then assigns it. The negotiated max_flows value is not currently enforced by WCM, so the product must bound console auto-provisioning separately.

Selection failure returns None; it is not an instruction to retry immediately. The application should distinguish temporary absence, hard requirements, capacity, and uncertain prior work in its own task policy.