From 9819169205b66c25a9f2458e0057b6f1301d9800 Mon Sep 17 00:00:00 2001 From: sebastianburckhardt Date: Wed, 4 Oct 2023 16:03:10 -0700 Subject: [PATCH 1/2] rename includeDeletedEntities to includeStatelessEntities and add comment explaining the meaning --- .../EntityTrackingStoreQueries.cs | 12 ++++++------ .../Entities/EntityBackendQueries.cs | 14 ++++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs b/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs index e6a146833..4a717119c 100644 --- a/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs +++ b/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs @@ -52,12 +52,12 @@ public EntityTrackingStoreQueries( public async override Task GetEntityAsync( EntityId id, bool includeState = false, - bool includeDeleted = false, + bool includeStateless = false, CancellationToken cancellation = default(CancellationToken)) { await this.ensureTaskHub(); OrchestrationState? state = (await this.trackingStore.GetStateAsync(id.ToString(), allExecutions: false, fetchInput: includeState)).FirstOrDefault(); - return await this.GetEntityMetadataAsync(state, includeDeleted, includeState); + return await this.GetEntityMetadataAsync(state, includeStateless, includeState); } public async override Task QueryEntitiesAsync(EntityQuery filter, CancellationToken cancellation) @@ -102,7 +102,7 @@ async ValueTask> ConvertResultsAsync(IEnumerable(); foreach (OrchestrationState entry in states) { - EntityMetadata? entityMetadata = await this.GetEntityMetadataAsync(entry, filter.IncludeDeleted, filter.IncludeState); + EntityMetadata? entityMetadata = await this.GetEntityMetadataAsync(entry, filter.IncludeStateless, filter.IncludeState); if (entityMetadata.HasValue) { entityResult.Add(entityMetadata.Value); @@ -196,7 +196,7 @@ bool OrchestrationIsRunning(OrchestrationStatus? status) }; } - async ValueTask GetEntityMetadataAsync(OrchestrationState? state, bool includeDeleted, bool includeState) + async ValueTask GetEntityMetadataAsync(OrchestrationState? state, bool includeStateless, bool includeState) { if (state == null) { @@ -205,7 +205,7 @@ bool OrchestrationIsRunning(OrchestrationStatus? status) if (!includeState) { - if (!includeDeleted) + if (!includeStateless) { // it is possible that this entity was logically deleted even though its orchestration was not purged yet. // we can check this efficiently (i.e. without deserializing anything) by looking at just the custom status @@ -239,7 +239,7 @@ bool OrchestrationIsRunning(OrchestrationStatus? status) string? serializedEntityState = ClientEntityHelpers.GetEntityState(serializedSchedulerState); // return the result to the user - if (!includeDeleted && serializedEntityState == null) + if (!includeStateless && serializedEntityState == null) { return null; } diff --git a/src/DurableTask.Core/Entities/EntityBackendQueries.cs b/src/DurableTask.Core/Entities/EntityBackendQueries.cs index 361667033..238b963eb 100644 --- a/src/DurableTask.Core/Entities/EntityBackendQueries.cs +++ b/src/DurableTask.Core/Entities/EntityBackendQueries.cs @@ -28,11 +28,11 @@ public abstract class EntityBackendQueries /// /// The ID of the entity to get. /// true to include entity state in the response, false to not. - /// whether to return metadata for a deleted entity (if such data was retained by the backend). + /// whether to include metadata for entities without user-defined state. /// The cancellation token to cancel the operation. /// a response containing metadata describing the entity. public abstract Task GetEntityAsync( - EntityId id, bool includeState = false, bool includeDeleted = false, CancellationToken cancellation = default); + EntityId id, bool includeState = false, bool includeStateless = false, CancellationToken cancellation = default); /// /// Queries entity instances based on the conditions specified in . @@ -102,12 +102,14 @@ public struct EntityQuery public bool IncludeState { get; set; } /// - /// Gets or sets a value indicating whether or not to include deleted entities. + /// Gets a value indicating whether to include metadata about entities that have no user-defined state. /// - /// - /// This setting is relevant only for providers which retain metadata for deleted entities ( is false). + /// Stateless entities occur when the storage provider is tracking metadata about an entity for synchronization purposes + /// even though the entity does not "logically" exist, in the sense that it has no application-defined state. + /// Stateless entities are usually transient. For example, they may be in the process of being created or deleted, or + /// they may have been locked by a critical section. /// - public bool IncludeDeleted { get; set; } + public bool IncludeStateless { get; set; } /// /// Gets or sets the desired size of each page to return. From 2c6dd3fa4cd87b48eeb128192fe571a31a6bc1f8 Mon Sep 17 00:00:00 2001 From: sebastianburckhardt Date: Wed, 4 Oct 2023 16:05:34 -0700 Subject: [PATCH 2/2] add backlogQueueSize and lockedBy to entity metadata --- .../EntityTrackingStoreQueries.cs | 10 +++++++++- src/DurableTask.Core/Entities/EntityBackendQueries.cs | 10 ++++++++++ .../Entities/StateFormat/EntityStatus.cs | 4 ++-- src/DurableTask.Core/TaskEntityDispatcher.cs | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs b/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs index 4a717119c..d2d33bead 100644 --- a/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs +++ b/src/DurableTask.AzureStorage/EntityTrackingStoreQueries.cs @@ -149,7 +149,7 @@ async ValueTask> ConvertResultsAsync(IEnumerable this.properties.EntityMessageReorderWindow); if (isEmptyEntity && safeToRemoveWithoutBreakingMessageSorterLogic) @@ -215,10 +215,14 @@ bool OrchestrationIsRunning(OrchestrationStatus? status) } } + EntityStatus? status = ClientEntityHelpers.GetEntityStatus(state.Status); + return new EntityMetadata() { EntityId = EntityId.FromString(state.OrchestrationInstance.InstanceId), LastModifiedTime = state.CreatedTime, + BacklogQueueSize = status?.BacklogQueueSize ?? 0, + LockedBy = status?.LockedBy, SerializedState = null, // we were instructed to not include the state }; } @@ -245,10 +249,14 @@ bool OrchestrationIsRunning(OrchestrationStatus? status) } else { + EntityStatus? status = ClientEntityHelpers.GetEntityStatus(state.Status); + return new EntityMetadata() { EntityId = EntityId.FromString(state.OrchestrationInstance.InstanceId), LastModifiedTime = state.CreatedTime, + BacklogQueueSize = status?.BacklogQueueSize ?? 0, + LockedBy = status?.LockedBy, SerializedState = serializedEntityState, }; } diff --git a/src/DurableTask.Core/Entities/EntityBackendQueries.cs b/src/DurableTask.Core/Entities/EntityBackendQueries.cs index 238b963eb..2ab17a6f1 100644 --- a/src/DurableTask.Core/Entities/EntityBackendQueries.cs +++ b/src/DurableTask.Core/Entities/EntityBackendQueries.cs @@ -66,6 +66,16 @@ public struct EntityMetadata /// public DateTime LastModifiedTime { get; set; } + /// + /// Gets the size of the backlog queue, if there is a backlog, and if that metric is supported by the backend. + /// + public int BacklogQueueSize { get; set; } + + /// + /// Gets the instance id of the orchestration that has locked this entity, or null if the entity is not locked. + /// + public string? LockedBy { get; set; } + /// /// Gets or sets the serialized state for this entity. Can be null if the query /// specified to not include the state, or to include deleted entities. diff --git a/src/DurableTask.Core/Entities/StateFormat/EntityStatus.cs b/src/DurableTask.Core/Entities/StateFormat/EntityStatus.cs index 47eb051d0..6075f14b9 100644 --- a/src/DurableTask.Core/Entities/StateFormat/EntityStatus.cs +++ b/src/DurableTask.Core/Entities/StateFormat/EntityStatus.cs @@ -38,7 +38,7 @@ public static bool TestEntityExists(string serializedJson) } /// - /// Whether this entity exists or not. + /// Whether this entity currently has a user-defined state or not. /// [DataMember(Name = EntityExistsProperyName, EmitDefaultValue = false)] public bool EntityExists { get; set; } @@ -47,7 +47,7 @@ public static bool TestEntityExists(string serializedJson) /// The size of the queue, i.e. the number of operations that are waiting for the current operation to complete. /// [DataMember(Name = "queueSize", EmitDefaultValue = false)] - public int QueueSize { get; set; } + public int BacklogQueueSize { get; set; } /// /// The instance id of the orchestration that currently holds the lock of this entity. diff --git a/src/DurableTask.Core/TaskEntityDispatcher.cs b/src/DurableTask.Core/TaskEntityDispatcher.cs index 10399a1c3..6981006cb 100644 --- a/src/DurableTask.Core/TaskEntityDispatcher.cs +++ b/src/DurableTask.Core/TaskEntityDispatcher.cs @@ -345,7 +345,7 @@ protected async Task OnProcessWorkItemAsync(TaskOrchestrationWorkItem work var entityStatus = new EntityStatus() { EntityExists = schedulerState.EntityExists, - QueueSize = schedulerState.Queue?.Count ?? 0, + BacklogQueueSize = schedulerState.Queue?.Count ?? 0, LockedBy = schedulerState.LockedBy, }; var serializedEntityStatus = JsonConvert.SerializeObject(entityStatus, Serializer.InternalSerializerSettings);