Operations Framework: Transient Operations
A transient operation is one that exists only in memory during command execution. It's not written to the operation log and won't be replayed on other hosts.
Transient operations are created by InMemoryOperationScope and have:
IsTransient = trueHasStoredOperation = false- UUID format:
{uuid}-local
When Are Operations Transient?
Operations become transient when:
- The command doesn't use
CreateOperationDbContext()(no database interaction) - The command explicitly disables storage with
Operation.MustStore(false)
cs
// Transient: No database context requested
[CommandHandler]
public virtual async Task IncrementCounter(
IncrementCommand command, CancellationToken cancellationToken = default)
{
if (Invalidation.IsActive) {
_ = GetCounter(command.Key, default);
return;
}
// No CreateOperationDbContext = transient operation
_counters.AddOrUpdate(command.Key, 1, (_, v) => v + 1);
}Persistent Operations
Operations become persistent when using CreateOperationDbContext:
cs
// Persistent: Uses database context
[CommandHandler]
public virtual async Task UpdateUser(
UpdateUserCommand command, CancellationToken cancellationToken = default)
{
if (Invalidation.IsActive) {
_ = GetUser(command.UserId, default);
return;
}
// CreateOperationDbContext = persistent operation
await using var dbContext = await DbHub.CreateOperationDbContext(cancellationToken);
var user = await dbContext.Users.FindAsync(command.UserId);
user.Name = command.Name;
await dbContext.SaveChangesAsync(cancellationToken);
}Comparison
| Aspect | Transient | Persistent |
|---|---|---|
| Scope Provider | InMemoryOperationScopeProvider | DbOperationScopeProvider<T> |
IsTransient | true | false |
| Stored in DB | No | Yes |
| Replayed on other hosts | No | Yes |
| Can have events | No | Yes |
| Can have items | Yes (in-memory only) | Yes (persisted) |
| UUID suffix | -local | (none) |
Controlling Storage
You can explicitly control whether an operation is stored:
cs
[CommandHandler]
public virtual async Task SomeCommand(
SomeCommand command, CancellationToken cancellationToken = default)
{
if (Invalidation.IsActive) { /* ... */ }
var context = CommandContext.GetCurrent();
// Even with CreateOperationDbContext, don't store this operation
context.Operation.MustStore(false);
await using var dbContext = await DbHub.CreateOperationDbContext(cancellationToken);
// ... do work ...
}Transient Operation Limitations
- No events: Calling
AddEvent()throwsTransientScopeOperationCannotHaveEvents - No cross-host invalidation: Only the local host sees the invalidation
- Items are memory-only:
Operation.Itemswon't be available on other hosts
Use transient operations for:
- Commands that modify only in-memory state
- Commands that don't need cluster-wide invalidation
- Commands where you handle invalidation through other means
Operation Completion
Whether transient or persistent, all operations go through completion:
The completion flow is the same for both transient and persistent operations, but only persistent operations are replayed on other hosts.
