// Intentionally NOT using async/await here, because we need yield return. // The magic is to only load all the pages, when it is really needed (e.g. when sorting is used). private static IEnumerable <DurableOrchestrationStatus> ListAllInstances(this IDurableClient durableClient, DateTime?timeFrom, DateTime?timeTill, bool showInput) { var queryCondition = new OrchestrationStatusQueryCondition() { PageSize = ListInstancesPageSize, ShowInput = showInput }; if (timeFrom.HasValue) { queryCondition.CreatedTimeFrom = timeFrom.Value; } if (timeTill.HasValue) { queryCondition.CreatedTimeTo = timeTill.Value; } OrchestrationStatusQueryResult response = null; do { queryCondition.ContinuationToken = response == null ? null : response.ContinuationToken; response = durableClient.ListInstancesAsync(queryCondition, CancellationToken.None).Result; foreach (var item in response.DurableOrchestrationState) { yield return(item); } }while (!string.IsNullOrEmpty(response.ContinuationToken)); }
//public const int MonitorTimeoutHours = 1; public static async Task <DurableOrchestrationStatus> FindJob <T>( this IDurableClient client, DateTime time, string workflowName, T creditOperation, bool runningOnly = true, bool confirmation = true) { var filter = runningOnly ? new List <OrchestrationRuntimeStatus> { OrchestrationRuntimeStatus.Running } : new List <OrchestrationRuntimeStatus>(); var offset = TimeSpan.FromMinutes(confirmation ? ExpirationMinutes : DefaultSpanMinutes); var condition = new OrchestrationStatusQueryCondition() { RuntimeStatus = filter, CreatedTimeFrom = time.Subtract(offset), CreatedTimeTo = time.Add(offset) }; var instances = await client.ListInstancesAsync(condition, new System.Threading.CancellationToken()); foreach (var instance in instances.DurableOrchestrationState) { if (instance.Input.ToObject <T>().Equals(creditOperation) && instance.Name == workflowName) { return(instance); } } return(null); }
public void Parse_OrchestrationStatusQueryCondition() { var runtimeStatus = new List <OrchestrationRuntimeStatus>() { OrchestrationRuntimeStatus.Failed, OrchestrationRuntimeStatus.Terminated, }; var createdTimeFrom = new DateTime(2019, 1, 3); var createdTimeTo = new DateTime(2019, 1, 4); var taskHubNames = new List <string>() { "baz", "qux", }; var condition = new OrchestrationStatusQueryCondition { RuntimeStatus = runtimeStatus, CreatedTimeFrom = createdTimeFrom, CreatedTimeTo = createdTimeTo, TaskHubNames = taskHubNames, }; var result = AzureStorageDurabilityProvider.ConvertWebjobsDurableConditionToAzureStorageCondition(condition); Assert.Equal(OrchestrationStatus.Failed, result.RuntimeStatus.First()); Assert.Equal(OrchestrationStatus.Terminated, result.RuntimeStatus.Last()); Assert.Equal(createdTimeFrom, result.CreatedTimeFrom); Assert.Equal(createdTimeTo, result.CreatedTimeTo); Assert.Equal(taskHubNames, result.TaskHubNames); }
public Task <OrchestrationStatusQueryResult> ListInstancesAsync(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { return(Task.FromResult(new OrchestrationStatusQueryResult { DurableOrchestrationState = _instances.Select(ToStatusObject).ToArray() })); }
public virtual async Task <string> runAction(IDurableOrchestrationClient starter, ILogger log) { var entLookup = Environment.GetEnvironmentVariable("LCU-ENTERPRISE-LOOKUP"); try { var listInstanceQuery = new OrchestrationStatusQueryCondition() { PageSize = 1000, RuntimeStatus = new[] { OrchestrationRuntimeStatus.Running, OrchestrationRuntimeStatus.Pending } }; var instances = await starter.ListInstancesAsync(listInstanceQuery, new System.Threading.CancellationToken()); var running = new HashSet <string>(instances.DurableOrchestrationState.Select(instance => instance.InstanceId)); var terminateTasks = running.Select(instanceId => { return(starter.TerminateAsync(instanceId, "Cleanup")); }); await Task.WhenAll(terminateTasks); while (running.Count > 0) { var results = await Task.WhenAll(instances.DurableOrchestrationState.Select(instance => starter.GetStatusAsync(instance.InstanceId))); foreach (var status in results) { // Remove any terminated or completed instances from the hashset if (status != null && status.RuntimeStatus != OrchestrationRuntimeStatus.Pending && status.RuntimeStatus != OrchestrationRuntimeStatus.Running) { running.Remove(status.InstanceId); } } await Task.Delay(TimeSpan.FromMilliseconds(1000)); } var instanceId = await starter.StartAction("RenewCertificatesOrchestration", new StateDetails() { EnterpriseLookup = entLookup }, new ExecuteActionRequest() { Arguments = new { EnterpriseLookup = entLookup }.JSONConvert <MetadataModel>() }, log); return(instanceId); } catch (Exception ex) { return(null); } }
public static async Task<IActionResult> PurgeCities( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "purgecities")] HttpRequest req, [DurableClient] IDurableClient client, ILogger log) { var queryCondition = new OrchestrationStatusQueryCondition() { InstanceIdPrefix = "Orch", }; PurgeHistoryResult result = await client.PurgeInstanceHistoryAsync(default,default,default);
public async Task Run( [TimerTrigger(PurgeFrequencyVariable)] TimerInfo myTimer, [DurableClient] IDurableOrchestrationClient client, ILogger log, CancellationToken hostCancellationToken) { EnsureArg.IsNotNull(client, nameof(client)); EnsureArg.IsNotNull(myTimer, nameof(myTimer)); EnsureArg.IsNotNull(log, nameof(log)); var orchestrationInstanceIdList = new List <string>(); log.LogInformation("Purging orchestration instance history at: {Timestamp}", _getUtcNow()); if (myTimer.IsPastDue) { log.LogWarning("Current function invocation is later than scheduled."); } // Specify conditions for orchestration instances. var condition = new OrchestrationStatusQueryCondition { RuntimeStatus = _purgeConfig.RuntimeStatuses, CreatedTimeFrom = DateTime.MinValue, CreatedTimeTo = _getUtcNow().AddDays(-_purgeConfig.MinimumAgeDays), ContinuationToken = null }; do { OrchestrationStatusQueryResult listOfOrchestrators = await client.ListInstancesAsync(condition, hostCancellationToken); condition.ContinuationToken = listOfOrchestrators.ContinuationToken; // Loop through the orchestration instances and purge them. foreach (DurableOrchestrationStatus orchestration in listOfOrchestrators.DurableOrchestrationState) { orchestrationInstanceIdList.Add(orchestration.InstanceId); await client.PurgeInstanceHistoryAsync(orchestration.InstanceId); } } while (condition.ContinuationToken != null); if (orchestrationInstanceIdList.Count != 0) { log.LogInformation("{Count} Durable Functions cleaned up successfully.", orchestrationInstanceIdList.Count); log.LogDebug("List of cleaned instance IDs: {list}", string.Join(", ", orchestrationInstanceIdList)); } else { log.LogInformation("No Orchestration instances found within given conditions."); } }
public static async Task GetAllStatuses( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req, [DurableClient] IDurableOrchestrationClient client, ILogger log) { var noFilter = new OrchestrationStatusQueryCondition(); var result = await client.ListInstancesAsync( noFilter, CancellationToken.None); foreach (var instance in result.DurableOrchestrationState) { log.LogInformation(JsonConvert.SerializeObject(instance)); } }
public static async Task AF_WAITINGFORAPPROVAL( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "raiseEvent/{instanceId}")] HttpRequest req, string instanceId, [DurableClient] IDurableOrchestrationClient client, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); var noFilter = new OrchestrationStatusQueryCondition(); OrchestrationStatusQueryResult result = await client.ListInstancesAsync( noFilter, CancellationToken.None); foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState) { log.LogInformation(JsonConvert.SerializeObject(instance)); } await client.RaiseEventAsync(instanceId, "WaitingForApproval", true); }
public static async Task <IActionResult> AF_GETINSTANCES( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "instances/{instanceId}")] HttpRequest req, string instanceId, [DurableClient] IDurableOrchestrationClient client, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); var noFilter = new OrchestrationStatusQueryCondition(); OrchestrationStatusQueryResult result = await client.ListInstancesAsync( noFilter, CancellationToken.None); foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState) { log.LogInformation(JsonConvert.SerializeObject(instance.InstanceId)); } return(new OkObjectResult(result.DurableOrchestrationState)); }
// Intentionally NOT using async/await here, because we need yield return. // The magic is to only load all the pages, when it is really needed (e.g. when sorting is used). private static IEnumerable <DurableOrchestrationStatus> ListAllInstances(this IDurableClient durableClient, DateTime?timeFrom, DateTime?timeTill, bool showInput, string[] statuses) { var queryCondition = new OrchestrationStatusQueryCondition() { PageSize = ListInstancesPageSize, ShowInput = showInput }; if (timeFrom.HasValue) { queryCondition.CreatedTimeFrom = timeFrom.Value; } if (timeTill.HasValue) { queryCondition.CreatedTimeTo = timeTill.Value; } if (statuses != null) { var runtimeStatuses = statuses.ToRuntimeStatuses().ToList(); // Durable Entities are always 'Running' if (statuses.Contains(DurableEntityRuntimeStatus, StringComparer.OrdinalIgnoreCase)) { runtimeStatuses.Add(OrchestrationRuntimeStatus.Running); } queryCondition.RuntimeStatus = runtimeStatuses; } OrchestrationStatusQueryResult response = null; do { queryCondition.ContinuationToken = response == null ? null : response.ContinuationToken; response = durableClient.ListInstancesAsync(queryCondition, CancellationToken.None).Result; foreach (var item in response.DurableOrchestrationState) { yield return(item); } }while (!string.IsNullOrEmpty(response.ContinuationToken)); }
public static async Task<IActionResult> CountCities( [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "countcities")] HttpRequest req, [DurableClient] IDurableClient client, ILogger log) { var queryCondition = new OrchestrationStatusQueryCondition() { InstanceIdPrefix = "Orch", }; int completed = 0; int pending = 0; int running = 0; int other = 0; do { OrchestrationStatusQueryResult result = await client.ListInstancesAsync(queryCondition, CancellationToken.None); queryCondition.ContinuationToken = result.ContinuationToken; foreach (var status in result.DurableOrchestrationState) { if (status.RuntimeStatus == OrchestrationRuntimeStatus.Pending) { pending++; } else if (status.RuntimeStatus == OrchestrationRuntimeStatus.Running) { running++; } else if (status.RuntimeStatus == OrchestrationRuntimeStatus.Completed) { completed++; } else { other++; } } } while (queryCondition.ContinuationToken != null); return new OkObjectResult($"{pending+running+completed+other} orchestration instances ({pending} pending, {running} running, {completed} completed, {other} other)\n"); }
public static async Task <HttpResponseMessage> HttpStart( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req, [DurableClient] IDurableOrchestrationClient starter, ILogger log) { OrchestrationStatusQueryCondition status = new OrchestrationStatusQueryCondition(); List <Microsoft.Azure.WebJobs.Extensions.DurableTask.OrchestrationRuntimeStatus> sL = new List <Microsoft.Azure.WebJobs.Extensions.DurableTask.OrchestrationRuntimeStatus>(); sL.Add(OrchestrationRuntimeStatus.Running); sL.Add(OrchestrationRuntimeStatus.Completed); status.RuntimeStatus = sL; string instanceId; // Function input comes from the request content. if (string.IsNullOrEmpty(_testMessage)) { instanceId = await starter.StartNewAsync("DurableFunctionsOrchestrationTicTacToe", null); _testMessage = instanceId; } else { instanceId = await starter.StartNewAsync <string>("DurableFunctionsOrchestrationTicTacToe", _testMessage, null); } var openInstances = await starter.GetStatusAsync(instanceId, true, false, false); log.LogInformation($"This is number of running instances: '{openInstances.RuntimeStatus}'"); log.LogInformation($"Started orchestration with ID = '{instanceId}'."); log.LogInformation($"Test Mesage = '{_testMessage}'."); return(starter.CreateCheckStatusResponse(req, instanceId)); }
public Task <OrchestrationStatusQueryResult> GetStatusAsync(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { return(this.innerClient.GetStatusAsync(condition, cancellationToken)); }
public Task <OrchestrationStatusQueryResult> GetStatusAsync(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { throw new NotImplementedException(); }
public override async Task <OrchestrationStatusQueryResult> GetOrchestrationStateWithPagination(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { if (condition == null) { throw new ArgumentNullException(nameof(condition)); } var query = new SqlOrchestrationQuery { PageSize = condition.PageSize, FetchInput = condition.ShowInput, CreatedTimeFrom = condition.CreatedTimeFrom, CreatedTimeTo = condition.CreatedTimeTo, InstanceIdPrefix = condition.InstanceIdPrefix, }; if (condition.RuntimeStatus?.Any() == true) { query.StatusFilter = new HashSet <OrchestrationStatus>(condition.RuntimeStatus.Select(status => (OrchestrationStatus)status)); } // The continuation token is just a page number. if (string.IsNullOrWhiteSpace(condition.ContinuationToken)) { query.PageNumber = 0; } else if (int.TryParse(condition.ContinuationToken, out int pageNumber)) { query.PageNumber = pageNumber; } else { throw new ArgumentException($"The continuation token '{condition.ContinuationToken}' is invalid.", nameof(condition)); } IReadOnlyCollection <OrchestrationState> results = await this.service.GetManyOrchestrationsAsync(query, cancellationToken); return(new OrchestrationStatusQueryResult { DurableOrchestrationState = results.Select(s => new DurableOrchestrationStatus { Name = s.Name, InstanceId = s.OrchestrationInstance.InstanceId, RuntimeStatus = (OrchestrationRuntimeStatus)s.OrchestrationStatus, CustomStatus = s.Status, CreatedTime = s.CreatedTime, LastUpdatedTime = s.LastUpdatedTime, Input = s.Input, Output = s.Output, }), ContinuationToken = results.Count == query.PageSize ? (query.PageNumber + 1).ToString() : null, }); }
public async Task MultiInstanceQueries() { DateTime startTime = DateTime.UtcNow; string prefix = $"{startTime:HHmmss}"; await Enumerable.Range(0, 5).ParallelForEachAsync(5, i => this.RunOrchestrationAsync( nameof(Functions.Sequence), instanceId: $"{prefix}.sequence.{i}")); // Extra delay to account for test flakiness in the GitHub CI (TODO: Why is this necessary?) await Task.Delay(TimeSpan.FromSeconds(1)); DateTime sequencesFinishedTime = SharedTestHelpers.GetCurrentDatabaseTimeUtc(); await Enumerable.Range(0, 5).ParallelForEachAsync(5, i => this.StartOrchestrationAsync( nameof(Functions.WaitForEvent), input: i.ToString(), instanceId: $"{prefix}.waiter.{i}")); IDurableClient client = await this.GetDurableClientAsync(); // Create one condition object and reuse it for multiple queries var condition = new OrchestrationStatusQueryCondition(); OrchestrationStatusQueryResult result; // Return all instances result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); // Test CreatedTimeTo filter condition.CreatedTimeTo = startTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Empty(result.DurableOrchestrationState); condition.CreatedTimeTo = sequencesFinishedTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(5, result.DurableOrchestrationState.Count()); condition.CreatedTimeTo = DateTime.UtcNow; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); // Test CreatedTimeFrom filter condition.CreatedTimeFrom = DateTime.UtcNow; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Empty(result.DurableOrchestrationState); condition.CreatedTimeFrom = sequencesFinishedTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(5, result.DurableOrchestrationState.Count()); condition.CreatedTimeFrom = startTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); // Test RuntimeStatus filter var statusFilters = new HashSet <OrchestrationRuntimeStatus>(new[] { OrchestrationRuntimeStatus.Failed, OrchestrationRuntimeStatus.Pending, OrchestrationRuntimeStatus.Terminated }); condition.RuntimeStatus = statusFilters; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Empty(result.DurableOrchestrationState); statusFilters.Add(OrchestrationRuntimeStatus.Running); result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(5, result.DurableOrchestrationState.Count()); Assert.All(result.DurableOrchestrationState, state => Assert.Equal(OrchestrationRuntimeStatus.Running, state.RuntimeStatus)); statusFilters.Add(OrchestrationRuntimeStatus.Completed); result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); statusFilters.Remove(OrchestrationRuntimeStatus.Running); result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(5, result.DurableOrchestrationState.Count()); Assert.All(result.DurableOrchestrationState, state => Assert.Equal(OrchestrationRuntimeStatus.Completed, state.RuntimeStatus)); statusFilters.Clear(); result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); // Test InstanceIdPrefix condition.InstanceIdPrefix = "Foo"; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Empty(result.DurableOrchestrationState); condition.InstanceIdPrefix = prefix; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.Equal(10, result.DurableOrchestrationState.Count()); // Test PageSize and ContinuationToken var instanceIds = new HashSet <string>(StringComparer.OrdinalIgnoreCase); condition.PageSize = 0; while (condition.PageSize++ < 10) { result = await client.ListInstancesAsync(condition, CancellationToken.None); int total = result.DurableOrchestrationState.Count(); Assert.Equal(condition.PageSize, total); // Make sure all instance IDs are unique Assert.All(result.DurableOrchestrationState, s => instanceIds.Add(s.InstanceId)); while (total < 10) { condition.ContinuationToken = result.ContinuationToken; result = await client.ListInstancesAsync(condition, CancellationToken.None); int count = result.DurableOrchestrationState.Count(); Assert.NotEqual(0, count); Assert.True(count <= condition.PageSize); total += count; Assert.True(total <= 10); Assert.All(result.DurableOrchestrationState, s => instanceIds.Add(s.InstanceId)); } condition.ContinuationToken = null; } // Test ShowInput condition.ShowInput = true; condition.CreatedTimeFrom = sequencesFinishedTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.All(result.DurableOrchestrationState, state => Assert.NotEqual(JValue.CreateNull(), state.Input)); condition.ShowInput = false; condition.CreatedTimeFrom = startTime; result = await client.ListInstancesAsync(condition, CancellationToken.None); Assert.All(result.DurableOrchestrationState, state => Assert.Equal(JValue.CreateNull(), state.Input)); }
/// <inheritdoc/> public async override Task <OrchestrationStatusQueryResult> GetOrchestrationStateWithPagination(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { var instanceQuery = new InstanceQuery( runtimeStatus: condition.RuntimeStatus?.Select(p => (OrchestrationStatus)Enum.Parse(typeof(OrchestrationStatus), p.ToString())).ToArray(), createdTimeFrom: (condition.CreatedTimeFrom == default) ? (DateTime?)null : condition.CreatedTimeFrom.ToUniversalTime(), createdTimeTo: (condition.CreatedTimeTo == default) ? (DateTime?)null : condition.CreatedTimeTo.ToUniversalTime(), instanceIdPrefix: condition.InstanceIdPrefix, fetchInput: condition.ShowInput); InstanceQueryResult result = await this.Service.QueryOrchestrationStatesAsync(instanceQuery, condition.PageSize, condition.ContinuationToken, cancellationToken); return(new OrchestrationStatusQueryResult() { DurableOrchestrationState = result.Instances.Select(ostate => ProviderUtils.ConvertOrchestrationStateToStatus(ostate)).ToList(), ContinuationToken = result.ContinuationToken, }); }