Customization
What can be customized
Section titled “What can be customized”Two important runtime extension points on a VU are:
http: the HTTP client used by stepsstep_strategy: the scheduler that decides which ready steps run next
In practice:
- the HTTP client defines how a VU sends requests and how those requests are configured
- the step strategy defines how the runtime selects ready steps during the execution loop
These two attributes are the main customization points for request behavior and step scheduling.
The http attribute can now be backed by either:
ReqwestClientfor request-oriented HTTP calls such asget(...)andpost(...)JsonRPCClientfor JSON-RPC method calls throughcall(...)
Default self.http
Section titled “Default self.http”Every VU has an http attribute. In the base runtime, the default is:
http = ReqwestClient()That means:
- the default HTTP implementation is based on
ReqwestClient - the runtime creates a separate client instance per VU
- the client is wrapped with instrumentation, so HTTP metrics are emitted automatically
In practice, steps call methods like:
await self.http.get("/catalog")await self.http.post("/auth", json=payload)How to override self.http
Section titled “How to override self.http”The most common override is to replace the class attribute with another ReqwestClient configuration:
from vikhry import ReqwestClient, VU
class DemoVU(VU): http = ReqwestClient(timeout=5.0)Then, in on_init(...), you can bind a base_url for that VU:
async def on_init(self, base_url: str) -> None: self.http = self.http(base_url=base_url)You can also provide your own HTTP client or factory instead of ReqwestClient. The runtime accepts:
- an object with async
request(...) - an object with
create(...)returning a client with asyncrequest(...) - a callable returning a client with async
request(...)
So custom transports are possible as long as they match the expected interface.
What ReqwestClient is
Section titled “What ReqwestClient is”ReqwestClient is a lazy template, not the final connected client itself.
It is used to define defaults such as:
base_urltimeout
When the VU starts, the runtime resolves that template into an instrumented per-user HTTP client.
Using JsonRPCClient
Section titled “Using JsonRPCClient”JsonRPCClient is another lazy runtime client template. It is intended for scenarios where the target system exposes a JSON-RPC endpoint instead of classic REST-style routes.
Example:
from vikhry import JsonRPCClient, VU, step
class DemoVU(VU): http = JsonRPCClient(timeout=5.0)
async def on_init(self, base_url: str) -> None: self.http = self.http(base_url=base_url)
@step(name="user.get") async def get_user(self) -> None: result = await self.http.call("user.get", {"user_id": 42}) if not result: raise RuntimeError("empty result")Important details:
JsonRPCClientrequires a non-emptybase_url- calls are sent as JSON-RPC
2.0POSTrequests - the primary API is
self.http.call(method, params=None, ...) paramscan be a list, tuple, dict, orNone
At runtime, the client builds requests like:
{ "jsonrpc": "2.0", "id": 1, "method": "user.get", "params": { "user_id": 42 }}The runtime also parses JSON-RPC responses and raises dedicated exceptions for protocol or RPC errors.
JSON-RPC metrics
Section titled “JSON-RPC metrics”JsonRPCClient is instrumented by the runtime in the same way as ReqwestClient, but metrics are emitted with JSON-RPC-specific fields.
Key differences:
- metric
sourceisjsonrpc - metric name is the RPC method name
- RPC failures use normalized
result_codevalues such asJSONRPC_-32000 - metric payload may include
rpc_error_codeandhttp_status
Default step_strategy
Section titled “Default step_strategy”Every VU also has a step_strategy attribute. The default is:
step_strategy = SequentialWeightedStrategy()This is the default scheduler for the VU step loop.
How SequentialWeightedStrategy works
Section titled “How SequentialWeightedStrategy works”The runtime first determines which steps are ready:
- all step names listed in
requiresmust already be completed - if
every_sis set, the step must wait until its next allowed execution time
After that:
- if no steps are ready, the VU sleeps briefly
- if one step is ready, that step runs
- if multiple steps are ready, one step is chosen using
weight
So the default behavior is sequential execution with weighted random choice among ready steps.
How to override step_strategy
Section titled “How to override step_strategy”You can replace the default strategy on the VU class:
from vikhry import ParallelReadyStrategy, VU
class DemoVU(VU): step_strategy = ParallelReadyStrategy()ParallelReadyStrategy runs all ready steps in the same scheduling tick instead of choosing only one.
You can also provide your own object implementing select(...) with the StepStrategy protocol.