-
Notifications
You must be signed in to change notification settings - Fork 0
Timeouts and Errors
Vyra follows a strict rule: no silent failures.
When a remote operation fails, times out or encounters a serialization issue, Vyra surfaces explicit, typed exceptions rather than returning null or hanging indefinitely.
All framework exceptions inherit from the unchecked VyraException:
classDiagram
direction TB
class VyraException {
base class for all Vyra errors
}
class VyraTimeoutException {
request exceeded its timeout
}
class VyraTransportException {
network failure / instance closed
}
class VyraSerializationException {
payload conversion failed / type not registered
}
class VyraRemoteException {
remote handler threw / server busy
}
VyraException <|-- VyraTimeoutException
VyraException <|-- VyraTransportException
VyraException <|-- VyraSerializationException
VyraException <|-- VyraRemoteException
Every failure is a typed exception. Catch VyraException at your top-level boundary, or handle each subtype separately.
| Exception | When it occurs | Recommended action |
|---|---|---|
VyraTimeoutException |
The remote service did not return a response before the specified timeout expired. | Retry if the operation is idempotent; otherwise alert or fail with a fallback. |
VyraTransportException |
Network-level failure while sending bytes to the underlying transport (e.g. broker disconnected). | Retry with exponential backoff; check transport connectivity. |
VyraSerializationException |
A message type was not registered via register(...), or JSON/binary encoding/decoding failed. |
Fix missing type registrations or incompatible class schemas. |
VyraRemoteException |
The remote service received the request, but the handler threw an exception or the server rejected the task. | Inspect remote.getCode() to determine cause. |
Every request(...) invocation requires a mandatory Duration timeout:
client.request("payment-service", req, PaymentResponse.class, Duration.ofSeconds(3));- Vyra’s timeout scheduler removes the pending request future from the correlation table.
- The caller’s
CompletionStagecompletes exceptionally withVyraTimeoutException. - Safe late discard: if the remote server eventually finishes and sends a response later, Vyra finds no matching correlation record and silently drops the late response. No memory is leaked.
When a remote service encounters an error, it returns a structured RemoteError envelope. Locally, this is unwrapped into a VyraRemoteException.
Instead of parsing exception text, check the machine-readable error code:
client.request("billing", req, InvoiceResponse.class, Duration.ofSeconds(3))
.whenComplete((res, throwable) -> {
if (throwable != null) {
Throwable cause = throwable instanceof CompletionException ? throwable.getCause() : throwable;
if (cause instanceof VyraRemoteException remote) {
switch (remote.getCode()) {
case HANDLER_ERROR ->
System.err.println("Handler logic threw an exception: " + remote.getMessage());
case SERVER_BUSY ->
System.err.println("Remote worker thread pool was full. Safe to retry with backoff.");
case UNKNOWN_MESSAGE_TYPE ->
System.err.println("Remote service does not know this message type!");
case SERIALIZATION_ERROR ->
System.err.println("Remote service could not deserialize payload.");
}
} else if (cause instanceof VyraTimeoutException) {
System.err.println("Request timed out after 3 seconds.");
}
} else {
System.out.println("Success: " + res);
}
});Because distributed systems can experience network partitions and worker restarts, design your retry strategies deliberately:
Read queries (GetPlayerRequest, FetchAccountBalance) can be safely retried upon VyraTimeoutException or VyraTransportException.
State-modifying actions (ChargeCreditCardRequest, TransferFundsRequest) must not be blindly retried on timeout, because the remote handler may have processed the request just before the timeout fired.
-
Best practice: include a unique
requestIdoridempotencyKeyinside your request record so the receiver can deduplicate operations.
RemoteError.Code.SERVER_BUSY indicates the remote server is alive, but its handler executor queue was temporarily full. This is a prime candidate for retrying after a brief exponential backoff delay.
Events sent via publish(...) are strictly at-most-once. If a subscriber fails while processing an event, the framework logs the failure and continues.
- Review the complete production recommendations in Best practices.
- Understand worker queue load balancing in Request / response.
- Learn how the handler executor isolates failures in Concurrency.
Vyra documentation