Error Handling
Clustron DKV operations return structured results using KvResult.
Instead of relying on exceptions, you handle outcomes explicitly based on status and metadata.
Understanding KvResultβ
Every operation returns a KvResult (or KvResult<T>).
var result = await client.PutAsync("key", "value");
Core Propertiesβ
Statusβ
result.Status
Indicates the outcome of the operation.
Common values:
SuccessNotFoundConflictInvalidInputUnavailableTransportErrorLocked
IsSuccessβ
if (result.IsSuccess)
{
// operation succeeded
}
Derived helper:
Status == Success AND no error
Errorβ
result.Error
- Contains error message if operation failed
- Useful for logging and debugging
Working with KvResult<T>β
var result = await client.GetAsync<int>("key");
if (result.IsSuccess)
{
Console.WriteLine(result.Value);
}
Valueis available only on success- Always check
IsSuccessfirst
Status-Based Handling (Important)β
You should handle results based on KvStatus.
NotFoundβ
if (result.Status == KvStatus.NotFound)
{
// key does not exist
}
Conflict (Optimistic Concurrency)β
if (result.Status == KvStatus.Conflict)
{
// retry logic
}
Occurs when:
IfMatchfails- Transaction commit fails
Lockedβ
if (result.Status == KvStatus.Locked)
{
// resource is locked
}
InvalidInputβ
if (result.Status == KvStatus.InvalidInput)
{
// developer or validation issue
}
Unavailable / TransportErrorβ
if (result.Status == KvStatus.Unavailable ||
result.Status == KvStatus.TransportError)
{
// transient issue β retry
}
Mutation Semanticsβ
Mutatedβ
if (result.Mutated)
{
// state actually changed
}
IsUpdateβ
if (result.IsUpdate)
{
// existing value was overwritten
}
Exampleβ
var result = await client.PutAsync("key", "value");
if (result.IsSuccess)
{
if (result.IsUpdate)
Console.WriteLine("Updated existing value");
else
Console.WriteLine("Created new value");
}
Version & Concurrencyβ
var version = result.Version;
- Used for optimistic concurrency
- Required for
IfMatchoperations
TTL & Expiryβ
var ttl = result.TimeToLive;
var expiry = result.ExpiryUtc;
- Indicates remaining lifetime
- Useful for monitoring and debugging
Metadata Accessβ
var metadata = result.Metadata;
Includes:
- Labels
- Entity
- Lease
- Other entry metadata
Retry Strategyβ
Retry only for transient or conflict scenarios.
Example: Retry on Conflictβ
for (int i = 0; i < 3; i++)
{
var result = await client.PutAsync(
"key",
"value",
Put.WithIfMatch(version));
if (result.IsSuccess)
break;
if (result.Status != KvStatus.Conflict)
break;
await Task.Delay(50);
}
When to Retryβ
Retry when:
ConflictLockedUnavailableTransportError
When NOT to Retryβ
Do not retry when:
InvalidInputNotFound(depends on logic)- Logical/business errors
Exceptions vs Resultsβ
| Scenario | Behavior |
|---|---|
| Expected outcome | KvResult |
| Unexpected failure | Exception |
Examples of exceptions:
- Serialization failure
- Invalid arguments
- Internal system errors
Best Practicesβ
- Always check
IsSuccessorStatus - Use
Statusfor precise handling - Retry only for transient failures
- Use
Versionfor safe updates - Use
Mutatedto detect actual changes
Key Takeawayβ
KvResult = Status + Metadata + Concurrency + Outcome
It is not just success/failure β it describes the full result of the operation.
Whatβs Nextβ
π Continue to Client Lifecycle to manage resources and usage patterns