From 046e600f907978bb91941c3b84da9bd914fdb017 Mon Sep 17 00:00:00 2001 From: Jacob Viau Date: Mon, 14 Aug 2023 09:41:53 -0700 Subject: [PATCH] Add TaskOrchestrationContext entity abstractions (#173) --- .../Entities/CallEntityOptions.cs | 17 +-- .../TaskOrchestrationEntityFeature.cs | 114 ++++++++++++++++++ src/Abstractions/TaskOrchestrationContext.cs | 7 ++ 3 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 src/Abstractions/Entities/TaskOrchestrationEntityFeature.cs diff --git a/src/Abstractions/Entities/CallEntityOptions.cs b/src/Abstractions/Entities/CallEntityOptions.cs index b9462b5b..abd9cfac 100644 --- a/src/Abstractions/Entities/CallEntityOptions.cs +++ b/src/Abstractions/Entities/CallEntityOptions.cs @@ -8,21 +8,8 @@ namespace Microsoft.DurableTask.Entities; /// public record CallEntityOptions { - /// - /// Gets options indicating whether to signal the entity or not. - /// - /// - /// Setting this to non-null will signal the entity without waiting for a response. - /// - /// - /// Signal without start time: - /// new CallEntityOptions { Signal = true }; - /// - /// - /// Signal with start time: - /// new CallEntityOptions { Signal = DateTimeOffset }; - /// - public SignalEntityOptions? Signal { get; init; } + // No call options at the moment. Keeping this class so we can ship with options in the API. This will + // allow us to easily add them later without adjusting API surface. } /// diff --git a/src/Abstractions/Entities/TaskOrchestrationEntityFeature.cs b/src/Abstractions/Entities/TaskOrchestrationEntityFeature.cs new file mode 100644 index 00000000..30df27b6 --- /dev/null +++ b/src/Abstractions/Entities/TaskOrchestrationEntityFeature.cs @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.DurableTask.Entities; + +/// +/// Feature for interacting with durable entities from an orchestration. +/// +public abstract class TaskOrchestrationEntityFeature +{ + /// + /// Calls an operation on an entity and waits for it to complete. + /// + /// The result type of the entity operation. + /// The target entity. + /// The name of the operation. + /// The operation input. + /// The call options. + /// The result of the entity operation. + public abstract Task CallEntityAsync( + EntityInstanceId id, string operationName, object? input = null, CallEntityOptions? options = null); + + /// + /// Calls an operation on an entity and waits for it to complete. + /// + /// The result type of the entity operation. + /// The target entity. + /// The name of the operation. + /// The call options. + /// The result of the entity operation. + public virtual Task CallEntityAsync( + EntityInstanceId id, string operationName, CallEntityOptions? options) + => this.CallEntityAsync(id, operationName, null, options); + + /// + /// Calls an operation on an entity and waits for it to complete. + /// + /// The target entity. + /// The name of the operation. + /// The operation input. + /// The call options. + /// A task that completes when the operation has been completed. + public abstract Task CallEntityAsync( + EntityInstanceId id, string operationName, object? input = null, CallEntityOptions? options = null); + + /// + /// Calls an operation on an entity and waits for it to complete. + /// + /// The target entity. + /// The name of the operation. + /// The call options. + /// A task that completes when the operation has been completed. + public virtual Task CallEntityAsync(EntityInstanceId id, string operationName, CallEntityOptions? options) + => this.CallEntityAsync(id, operationName, null, options); + + /// + /// Calls an operation on an entity, but does not wait for completion. + /// + /// The target entity. + /// The name of the operation. + /// The operation input. + /// The signal options. + /// + /// A task that represents scheduling of the signal operation. Dependening on implementation, this may complete + /// either when the operation has been signalled, or when the signal action has been enqueued by the context. + /// + public abstract Task SignalEntityAsync( + EntityInstanceId id, string operationName, object? input = null, SignalEntityOptions? options = null); + + /// + /// Calls an operation on an entity, but does not wait for completion. + /// + /// The target entity. + /// The name of the operation. + /// The signal options. + /// + /// A task that represents scheduling of the signal operation. Dependening on implementation, this may complete + /// either when the operation has been signalled, or when the signal action has been enqueued by the context. + /// + public virtual Task SignalEntityAsync( + EntityInstanceId id, string operationName, SignalEntityOptions? options) + => this.SignalEntityAsync(id, operationName, null, options); + + /// + /// Acquires one or more entity locks. + /// + /// The entity IDs to lock. + /// An async-disposable which can be disposed to release the lock. + public abstract Task LockEntitiesAsync(IEnumerable entityIds); + + /// + /// Acquires one or more entity locks. + /// + /// The entity IDs to lock. + /// An async-disposable which can be disposed to release the lock. + public virtual Task LockEntitiesAsync(params EntityInstanceId[] entityIds) + => this.LockEntitiesAsync((IEnumerable)entityIds); // let the implementation decide how to handle nulls. + + /// + /// Gets a value indicating whether this orchestration is in a critical section, and if true, any entity locks are + /// owned by this instance. + /// + /// The list of locked entities. + /// True if any locks are owned, false otherwise. + public abstract bool InCriticalSection([NotNullWhen(true)] out IReadOnlyList? entityIds); + + /// + /// Gets a value indicating whether this orchestration is in a critical section. + /// + /// True if any locks are owned, false otherwise. + public virtual bool InCriticalSection() => this.InCriticalSection(out _); +} diff --git a/src/Abstractions/TaskOrchestrationContext.cs b/src/Abstractions/TaskOrchestrationContext.cs index b3f139dc..15ba1ddc 100644 --- a/src/Abstractions/TaskOrchestrationContext.cs +++ b/src/Abstractions/TaskOrchestrationContext.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Microsoft.DurableTask.Entities; using Microsoft.Extensions.Logging; namespace Microsoft.DurableTask; @@ -58,6 +59,12 @@ public abstract class TaskOrchestrationContext /// public abstract bool IsReplaying { get; } + /// + /// Gets the entity feature, for interacting with entities. + /// + public virtual TaskOrchestrationEntityFeature Entities => + throw new NotSupportedException($"Durable entities are not supported by {this.GetType()}."); + /// /// Gets the logger factory for this context. ///