/// <summary>
        ///     Purges orchestration instance state and history for orchestrations older than the specified threshold time.
        /// </summary>
        /// <param name="thresholdDateTimeUtc">Threshold date time in UTC</param>
        /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
        /// <returns></returns>
        public async Task PurgeOrchestrationInstanceHistoryAsync(DateTime thresholdDateTimeUtc,
                                                                 OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            ThrowIfInstanceStoreNotConfigured();

            TableContinuationToken continuationToken = null;

            TraceHelper.Trace(TraceEventType.Information,
                              () =>
                              "Purging orchestration instances before: " + thresholdDateTimeUtc + ", Type: " + timeRangeFilterType);

            int purgeCount = 0;

            do
            {
                TableQuerySegment <OrchestrationStateEntity> resultSegment =
                    (await tableClient.QueryOrchestrationStatesSegmentedAsync(
                         new OrchestrationStateQuery()
                         .AddTimeRangeFilter(DateTime.MinValue, thresholdDateTimeUtc, timeRangeFilterType),
                         continuationToken, 100)
                     .ConfigureAwait(false));

                continuationToken = resultSegment.ContinuationToken;

                if (resultSegment.Results != null)
                {
                    await PurgeOrchestrationHistorySegmentAsync(resultSegment).ConfigureAwait(false);

                    purgeCount += resultSegment.Results.Count;
                }
            } while (continuationToken != null);

            TraceHelper.Trace(TraceEventType.Information, () => "Purged " + purgeCount + " orchestration histories");
        }
        public Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            if (timeRangeFilterType != OrchestrationStateTimeRangeFilterType.OrchestrationCompletedTimeFilter)
            {
                throw new NotSupportedException("Purging is supported only for Orchestration completed time filter.");
            }

            return(this.instanceStore.PurgeOrchestrationHistoryEventsAsync(thresholdDateTimeUtc));
        }
        public override async Task PurgeOrchestrationHistoryAsync(
            DateTime maxThresholdDateTimeUtc,
            OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            using SqlConnection connection = await this.GetAndOpenConnectionAsync();

            using SqlCommand command = this.GetSprocCommand(connection, "dt.PurgeInstanceStateByTime");

            command.Parameters.Add("@ThresholdTime", SqlDbType.DateTime2).Value = maxThresholdDateTimeUtc;
            command.Parameters.Add("@FilterType", SqlDbType.TinyInt).Value      = (int)timeRangeFilterType;

            await SqlUtils.ExecuteNonQueryAsync(command, this.traceHelper);
        }
        /// <summary>
        ///     Adds a time range filter on the returned orchestrations
        /// </summary>
        /// <param name="startTime">Start of the time range to filter by</param>
        /// <param name="endTime">End of the time range to filter by</param>
        /// <param name="filterType">Type of orchestration timestamp to apply filter on</param>
        /// <returns></returns>
        public OrchestrationStateQuery AddTimeRangeFilter(DateTime startTime, DateTime endTime,
                                                          OrchestrationStateTimeRangeFilterType filterType)
        {
            if (FilterMap.ContainsKey(typeof(OrchestrationStateTimeRangeFilter)))
            {
                throw new ArgumentException("Cannot add more than one time range filters");
            }

            FilterMap.Add(typeof(OrchestrationStateTimeRangeFilter),
                          new OrchestrationStateTimeRangeFilter
            {
                StartTime  = startTime,
                EndTime    = endTime,
                FilterType = filterType
            });

            return(this);
        }
示例#5
0
        public override Task PurgeOrchestrationHistoryAsync(
            OrchestrationDbContext dbContext,
            DateTime thresholdDateTimeUtc,
            OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            var executions = timeRangeFilterType switch
            {
                OrchestrationStateTimeRangeFilterType.OrchestrationCreatedTimeFilter =>
                dbContext.Executions.Where(e => e.CreatedTime < thresholdDateTimeUtc).ToArray(),
                OrchestrationStateTimeRangeFilterType.OrchestrationLastUpdatedTimeFilter =>
                dbContext.Executions.Where(e => e.LastUpdatedTime < thresholdDateTimeUtc).ToArray(),
                OrchestrationStateTimeRangeFilterType.OrchestrationCompletedTimeFilter =>
                dbContext.Executions.Where(e => e.CompletedTime < thresholdDateTimeUtc).ToArray(),
                _ => throw new NotImplementedException()
            };

            dbContext.Executions.RemoveRange(executions);
            dbContext.SaveChanges();
            return(Task.CompletedTask);
        }
示例#6
0
        public override async Task PurgeOrchestrationHistoryAsync(
            OrchestrationDbContext dbContext,
            DateTime thresholdDateTimeUtc,
            OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            switch (timeRangeFilterType)
            {
            case OrchestrationStateTimeRangeFilterType.OrchestrationCreatedTimeFilter:
                await dbContext.Database.ExecuteSqlInterpolatedAsync($"DELETE FROM Executions WHERE CreatedTime < {thresholdDateTimeUtc}");

                break;

            case OrchestrationStateTimeRangeFilterType.OrchestrationLastUpdatedTimeFilter:
                await dbContext.Database.ExecuteSqlInterpolatedAsync($"DELETE FROM Executions WHERE LastUpdatedTime < {thresholdDateTimeUtc}");

                break;

            case OrchestrationStateTimeRangeFilterType.OrchestrationCompletedTimeFilter:
                await dbContext.Database.ExecuteSqlInterpolatedAsync($"DELETE FROM Executions WHERE CompletedTime < {thresholdDateTimeUtc}");

                break;
            }
        }
        /// <summary>
        /// Purges history from storage for given time range
        /// </summary>
        /// <param name="thresholdDateTimeUtc">The datetime in UTC to use as the threshold for purging history</param>
        /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
        /// <returns>The number of history events purged.</returns>
        public async Task <int> PurgeOrchestrationHistoryEventsAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            TableContinuationToken continuationToken = null;

            int purgeCount = 0;

            do
            {
                TableQuerySegment <AzureTableOrchestrationStateEntity> resultSegment =
                    (await tableClient.QueryOrchestrationStatesSegmentedAsync(
                         new OrchestrationStateQuery()
                         .AddTimeRangeFilter(DateTimeUtils.MinDateTime, thresholdDateTimeUtc, timeRangeFilterType),
                         continuationToken, 100)
                     .ConfigureAwait(false));

                continuationToken = resultSegment.ContinuationToken;

                if (resultSegment.Results != null)
                {
                    await PurgeOrchestrationHistorySegmentAsync(resultSegment).ConfigureAwait(false);

                    purgeCount += resultSegment.Results.Count;
                }
            } while (continuationToken != null);

            return(purgeCount);
        }
 /// <inheritdoc />
 public Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
 {
     throw new NotImplementedException();
 }
示例#9
0
        public async Task PurgesInstancesByStatus(OrchestrationStateTimeRangeFilterType filterType)
        {
            DateTime startTime = DateTime.UtcNow;

            var events = new ConcurrentDictionary <string, TaskCompletionSource <bool> >();

            // Waits for an external event and then either completes or fails depending on that event
            IReadOnlyList <TestInstance <string> > instances = await this.testService.RunOrchestrations(
                count : 30, // ideally some multiple of 3
                instanceIdGenerator : i => $"InstanceToPurge_{i:00}",
                inputGenerator : i => $"Hello, world {i}",
                orchestrationName : "SimpleDelay",
                version : string.Empty,
                implementation : async(ctx, input) =>
            {
                var tcs = new TaskCompletionSource <bool>();
                events[ctx.OrchestrationInstance.InstanceId] = tcs;

                bool shouldFail = await tcs.Task;
                if (shouldFail)
                {
                    throw new Exception("Kah-BOOOOOM!!!");
                }

                return(shouldFail);
            },
                onEvent : (ctx, name, value) =>
            {
                events[ctx.OrchestrationInstance.InstanceId].SetResult(bool.Parse(value));
            });

            await Task.WhenAll(instances.Select(instance => instance.WaitForStart()));

            // Try to purge the instance and check that it still exists
            await this.testService.PurgeAsync(startTime, filterType);

            foreach (TestInstance <string> instance in instances)
            {
                OrchestrationState runningState = await instance.GetStateAsync();

                Assert.Equal(OrchestrationStatus.Running, runningState.OrchestrationStatus);
            }

            TimeSpan timeout = TimeSpan.FromSeconds(30);

            // We want to test a mix of completed, failed, and terminated instances to make sure they are all handled correctly.
            var tasks = new List <Task>();

            for (int i = 0; i < instances.Count; i++)
            {
                int index = i;
                tasks.Add(Task.Run(async() =>
                {
                    TestInstance <string> instance = instances[index];
                    if (index % 3 == 0)
                    {
                        // Complete the instance
                        await instance.RaiseEventAsync("Action", false);
                        await instance.WaitForCompletion(timeout, OrchestrationStatus.Completed);
                    }
                    else if (index % 3 == 1)
                    {
                        // Fail the instance
                        await instance.RaiseEventAsync("Action", true);
                        await instance.WaitForCompletion(timeout, OrchestrationStatus.Failed);
                    }
                    else
                    {
                        // Terminate the instance
                        await instance.TerminateAsync("Terminated!");
                        await instance.WaitForCompletion(timeout, OrchestrationStatus.Terminated);
                    }
                }));
            }

            // Wait for all instances to transition into their final state
            await Task.WhenAll(tasks);

            // This time-based purge should remove all the instances
            await this.testService.PurgeAsync(startTime, filterType);

            foreach (TestInstance <string> instance in instances)
            {
                OrchestrationState purgedState = await instance.GetStateAsync();

                Assert.Null(purgedState);
            }

            // One more purge, just to make sure there are no failures when there is nothing left to purge
            await this.testService.PurgeAsync(startTime, filterType);
        }
示例#10
0
 /// <summary>
 ///     Purges orchestration instance state and history for orchestrations older than the specified threshold time.
 /// </summary>
 /// <param name="thresholdDateTimeUtc">Threshold date time in UTC</param>
 /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
 /// <returns></returns>
 /// <exception cref="InvalidOperationException">Thrown if instance store not configured</exception>
 public Task PurgeOrchestrationInstanceHistoryAsync(DateTime thresholdDateTimeUtc,
                                                    OrchestrationStateTimeRangeFilterType timeRangeFilterType)
 {
     return(this.serviceClient.PurgeOrchestrationHistoryAsync(thresholdDateTimeUtc, timeRangeFilterType));
 }
示例#11
0
 /// <inheritdoc />
 public override Task PurgeHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
 {
     return(this.instanceStore.PurgeOrchestrationHistoryEventsAsync(thresholdDateTimeUtc, timeRangeFilterType));
 }
        /// <summary>
        /// Purges orchestration instance state and history for orchestrations older than the specified threshold time.
        /// Also purges the blob storage.
        /// </summary>
        /// <param name="thresholdDateTimeUtc">Threshold date time in UTC</param>
        /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
        public async Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            List <Task <HttpResponseMessage> > allTasks = new List <Task <HttpResponseMessage> >();

            foreach (var endpoint in await this.GetAllEndpointsAsync(CancellationToken.None))
            {
                var uri  = $"{endpoint.ToString()}/{GetHistoryFragment()}";
                var task = this.HttpClient.PostAsJsonAsync(uri, new PurgeOrchestrationHistoryParameters {
                    ThresholdDateTimeUtc = thresholdDateTimeUtc, TimeRangeFilterType = timeRangeFilterType
                });
                allTasks.Add(task);
            }

            var responses = await Task.WhenAll(allTasks.ToArray());

            foreach (var response in responses)
            {
                response.EnsureSuccessStatusCode();
            }
        }
示例#13
0
 public Task PurgeAsync(DateTime minimumThreshold, OrchestrationStateTimeRangeFilterType filterType)
 {
     return(this.client.PurgeOrchestrationInstanceHistoryAsync(
                minimumThreshold,
                filterType));
 }
        /// <summary>
        /// Purges history from storage for given time range
        /// </summary>
        /// <param name="thresholdDateTimeUtc">The datetime in UTC to use as the threshold for purging history</param>
        /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
        /// <returns>The number of history events purged.</returns>
        public async Task <int> PurgeOrchestrationHistoryEventsAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            var purgeCount = await Client.PurgeOrchestrationInstanceHistoryAsync(thresholdDateTimeUtc, timeRangeFilterType);

            return(purgeCount);
        }
 /// <inheritdoc />
 public override Task PurgeHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
 {
     throw new NotSupportedException();
 }
示例#16
0
        public async Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            var request = new PurgeOrchestrationHistoryRequest
            {
                ThresholdDateTimeUtc = ToTimestamp(thresholdDateTimeUtc),
                TimeRangeFilterType  = (OrchestrationTimeFilterType)timeRangeFilterType
            };

            await _client.PurgeOrchestrationHistoryAsync(request);
        }
示例#17
0
        /// <summary>
        ///     Purges orchestration instance state and history for orchestrations older than the specified threshold time.
        /// </summary>
        /// <param name="thresholdDateTimeUtc">Threshold date time in UTC</param>
        /// <param name="timeRangeFilterType">What to compare the threshold date time against</param>
        /// <returns></returns>
        public async Task PurgeOrchestrationInstanceHistoryAsync(DateTime thresholdDateTimeUtc,
            OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            ThrowIfInstanceStoreNotConfigured();

            TableContinuationToken continuationToken = null;

            TraceHelper.Trace(TraceEventType.Information,
                () =>
                    "Purging orchestration instances before: " + thresholdDateTimeUtc + ", Type: " + timeRangeFilterType);

            int purgeCount = 0;
            do
            {
                TableQuerySegment<OrchestrationStateEntity> resultSegment =
                    (await tableClient.QueryOrchestrationStatesSegmentedAsync(
                        new OrchestrationStateQuery()
                            .AddTimeRangeFilter(DateTime.MinValue, thresholdDateTimeUtc, timeRangeFilterType),
                        continuationToken, 100)
                        .ConfigureAwait(false));

                continuationToken = resultSegment.ContinuationToken;

                if (resultSegment.Results != null)
                {
                    await PurgeOrchestrationHistorySegmentAsync(resultSegment).ConfigureAwait(false);
                    purgeCount += resultSegment.Results.Count;
                }
            } while (continuationToken != null);

            TraceHelper.Trace(TraceEventType.Information, () => "Purged " + purgeCount + " orchestration histories");
        }
 public async Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
 {
     using (var dbContext = _dbContextFactory())
     {
         await _dbContextExtensions.PurgeOrchestrationHistoryAsync(dbContext, thresholdDateTimeUtc, timeRangeFilterType);
     }
 }
 public abstract Task PurgeOrchestrationHistoryAsync(OrchestrationDbContext dbContext, DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType);
        /// <summary>
        ///     Adds a time range filter on the returned orchestrations
        /// </summary>
        /// <param name="startTime">Start of the time range to filter by</param>
        /// <param name="endTime">End of the time range to filter by</param>
        /// <param name="filterType">Type of orchestration timestamp to apply filter on</param>
        /// <returns></returns>
        public OrchestrationStateQuery AddTimeRangeFilter(DateTime startTime, DateTime endTime,
            OrchestrationStateTimeRangeFilterType filterType)
        {
            if (FilterMap.ContainsKey(typeof (OrchestrationStateTimeRangeFilter)))
            {
                throw new ArgumentException("Cannot add more than one time range filters");
            }

            FilterMap.Add(typeof (OrchestrationStateTimeRangeFilter),
                new OrchestrationStateTimeRangeFilter
                {
                    StartTime = startTime,
                    EndTime = endTime,
                    FilterType = filterType
                });

            return this;
        }
 /// <inheritdoc />
 public abstract Task PurgeHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType);
示例#22
0
        /// <inheritdoc />
        public async Task <int> PurgeOrchestrationHistoryEventsAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType)
        {
            var deleteStatement = $@"DELETE h FROM {settings.WorkItemTableName} h JOIN {settings.OrchestrationStateTableName} e ON e.InstanceId = h.InstanceId AND e.ExecutionId = h.ExecutionId ";

            switch (timeRangeFilterType)
            {
            case OrchestrationStateTimeRangeFilterType.OrchestrationCompletedTimeFilter:
                deleteStatement += "WHERE e.CompletedTime <= @thresholdDateTimeUtc";
                break;

            case OrchestrationStateTimeRangeFilterType.OrchestrationCreatedTimeFilter:
                deleteStatement += "WHERE e.CreatedTime <= @thresholdDateTimeUtc";
                break;

            case OrchestrationStateTimeRangeFilterType.OrchestrationLastUpdatedTimeFilter:
                deleteStatement += "WHERE e.LastUpdatedTime <= @thresholdDateTimeUtc";
                break;

            default:
                throw new ArgumentOutOfRangeException($"Unknown {nameof(timeRangeFilterType)} value: {timeRangeFilterType}");
            }

            using (var connection = await settings.GetDatabaseConnection())
                using (var command = connection.CreateCommand())
                {
                    command.AddParameter("thresholdDateTimeUtc", thresholdDateTimeUtc)
                    .CommandText = deleteStatement;

                    await connection.OpenAsync();

                    return(await command.ExecuteNonQueryAsync());
                }
        }