public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var command = functionContext.GetInput <OrchestratorProjectDeleteCommand>(); var commandResult = command.CreateResult(); using (log.BeginCommandScope(command)) { functionContext.SetCustomStatus($"Refreshing project", log); var project = commandResult.Result = (await functionContext .GetProjectAsync(command.ProjectId, allowUnsafe: true) .ConfigureAwait(true)) ?? command.Payload; try { try { functionContext.SetCustomStatus("Sending commands", log); var providerCommand = new ProviderProjectDeleteCommand ( command.User.PopulateExternalModel(), project.PopulateExternalModel(), command.CommandId ); var providerResults = await functionContext .SendProviderCommandAsync <ProviderProjectDeleteCommand, ProviderProjectDeleteCommandResult>(providerCommand, project) .ConfigureAwait(true); } finally { functionContext.SetCustomStatus("Deleting project", log); await functionContext .DeleteProjectAsync(project) .ConfigureAwait(true); functionContext.SetCustomStatus($"Deleting project identity", log); await functionContext .CallActivityWithRetryAsync(nameof(ProjectIdentityDeleteActivity), project) .ConfigureAwait(true); functionContext.SetCustomStatus("Deleting resources", log); await functionContext.DeleteResourcesAsync ( false, // we are not going to wait for this operation GetResourceGroupId(project?.ResourceGroup?.Id) ) .ConfigureAwait(true); } } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); throw; } finally { var commandException = commandResult.Errors?.ToException(); if (commandException is null) { functionContext.SetCustomStatus($"Command succeeded", log); } else { functionContext.SetCustomStatus($"Command failed: {commandException.Message}", log, commandException); } functionContext.SetOutput(commandResult); } } }
public override async Task <ICommandResult> HandleAsync(ProjectDestroyCommand command, IAsyncCollector <ICommand> commandQueue, IDurableOrchestrationContext orchestrationContext, ILogger log) { if (command is null) { throw new ArgumentNullException(nameof(command)); } if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var commandResult = command.CreateResult(); using (await orchestrationContext.LockContainerDocumentAsync(command.Payload).ConfigureAwait(true)) { // just to make sure we are dealing with the latest version // of the Project entity, we re-fetch the entity and // use the passed in one as a potential fallback. commandResult.Result = (await orchestrationContext .CallActivityWithRetryAsync <Project>(nameof(ProjectGetActivity), new ProjectGetActivity.Input() { Id = command.Payload.Id, Organization = command.Payload.Organization }) .ConfigureAwait(true)) ?? command.Payload; if (commandResult.Result.Deleted.HasValue) { try { commandResult.Result = await UpdateProjectAsync(commandResult.Result, ResourceState.Deprovisioning) .ConfigureAwait(true); var components = await componentRepository .ListAsync(commandResult.Result.Id, includeDeleted : true) .ToArrayAsync() .ConfigureAwait(true); if (components.Any(c => c.ResourceState.IsActive())) { // at least one of the component in the context of this // project are in an active state. we postpone the project // destroy operation until all components are gone or // in a deprovisioned state. await orchestrationContext .ContinueAsNew(command, TimeSpan.FromMinutes(1)) .ConfigureAwait(true); } else if (components.Any(c => c.ResourceState != ResourceState.Deprovisioned)) { // at least one of the components reached a final state // other than deprovisioned. we simple cant destroy the // project in this situation but need to switch back into // a provisioned state to give to user to fix issues // on the component level commandResult.Result = await UpdateProjectAsync(commandResult.Result, ResourceState.Provisioned, restore : true) .ConfigureAwait(true); } else { // we are good to delete project related resources and // finally delete the project itself in our data store await orchestrationContext .CallActivityWithRetryAsync(nameof(ProjectDestroyActivity), new ProjectDestroyActivity.Input() { Project = commandResult.Result }) .ConfigureAwait(true); commandResult.Result = await UpdateProjectAsync(commandResult.Result, ResourceState.Deprovisioned) .ConfigureAwait(true); } } catch { commandResult.Result = await UpdateProjectAsync(commandResult.Result, ResourceState.Failed, restore : true) .ConfigureAwait(true); throw; } } } return(commandResult); Task <Project> UpdateProjectAsync(Project project, ResourceState?resourceState = null, bool restore = false) { project.ResourceState = resourceState ?? project.ResourceState; if (restore) { project.Deleted = null; project.TTL = null; } return(orchestrationContext.CallActivityWithRetryAsync <Project>(nameof(ProjectSetActivity), new ProjectSetActivity.Input() { Project = commandResult.Result, ResourceState = ResourceState.Deprovisioned })); } }
public static Task <IEnumerable <Project> > ListProjectsAsync(this IDurableOrchestrationContext durableOrchestrationContext, IList <string> projectIds) => durableOrchestrationContext.CallActivityWithRetryAsync <IEnumerable <Project> >(nameof(ProjectListByIdActivity), projectIds);
public static Task <UserDocument> DeleteUserAsync(this IDurableOrchestrationContext orchestrationContext, UserDocument user, bool allowUnsafe = false) => orchestrationContext.IsLockedBy <UserDocument>(user.Id.ToString()) || allowUnsafe ? orchestrationContext.CallActivityWithRetryAsync <UserDocument>(nameof(UserDeleteActivity), user) : throw new NotSupportedException($"Unable to delete user '{user.Id}' without acquired lock");
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var command = functionContext.GetInput <ProviderProjectCreateCommand>(); var commandResult = command.CreateResult(); var commandLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); using (log.BeginCommandScope(command)) { try { functionContext.SetCustomStatus("Deploy resources", commandLog); var deploymentOutput = await functionContext .CallDeploymentAsync(nameof(ProjectCreateActivity), command.Payload) .ConfigureAwait(true); if (deploymentOutput.TryGetValue("resourceId", out var resourceId)) { functionContext.SetCustomStatus("Updating user permissions", commandLog); await functionContext .CallActivityWithRetryAsync(nameof(ProjectUsersActivity), (command.Payload, resourceId?.ToString())) .ConfigureAwait(true); } commandResult.Result = new ProviderOutput { Properties = deploymentOutput.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToString()) }; } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); throw exc.AsSerializable(); } finally { var commandException = commandResult.Errors?.ToException(); if (commandException is null) { functionContext.SetCustomStatus($"Command succeeded", commandLog); } else { functionContext.SetCustomStatus($"Command failed: {commandException.Message}", commandLog, commandException); } functionContext.SetOutput(commandResult); } } }
public static Task <ProviderDocument> DeleteProviderAsync(this IDurableOrchestrationContext orchestrationContext, ProviderDocument provider, bool allowUnsafe = false) => orchestrationContext.IsLockedBy <ProviderDocument>(provider.Id) || allowUnsafe ? orchestrationContext.CallActivityWithRetryAsync <ProviderDocument>(nameof(ProviderDeleteActivity), provider) : throw new NotSupportedException($"Unable to delete provider '{provider.Id}' without acquired lock");
public static async Task <object> Run( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var(maximumRunDuration, aciRequirements) = context.GetInput <(DateTime, ACIRequirements)>(); var(containerGroupInfo, pollingInterval, maxProcessingTime) = aciRequirements; var(resourceGroupName, containerGroupName) = (containerGroupInfo.ResourceGroupName, containerGroupInfo.ContainerGroupName); var containerGroupStatus = await context.CallActivityWithRetryAsync <ContainerGroupStatus>( nameof(Activity_GetACIStatus), new RetryOptions(TimeSpan.FromSeconds(30), 3) { RetryTimeout = TimeSpan.FromSeconds(30) }, containerGroupInfo); // if the container group has finished, return success status if (containerGroupStatus.Containers[0]?.CurrentState?.State == "Terminated") { var logContent = await context.CallActivityAsync <string>(nameof(Activity_GetACILogs), containerGroupInfo); bool isSuccess = CheckSuccessCode(logContent); if (isSuccess) { return(new { Success = true }); } if (!context.IsReplaying) { log.LogError($"logs: {logContent}"); } //return new { Success = false, Message = logContent }; throw new ApplicationException($"logs: {logContent}"); } // the container group has not finished - sleep for N duration using (var cts = new CancellationTokenSource()) { await context.CreateTimer(context.CurrentUtcDateTime.AddMinutes(pollingInterval), cts.Token); } // end workflow if we've been waiting too long if (context.CurrentUtcDateTime > maximumRunDuration) { if (!context.IsReplaying) { log.LogWarning($"Exceeded processing time { maxProcessingTime } minutes."); } //return new { Success = false, Message = "Exceeded processing time." } ; throw new TimeoutException($"Exceeded processing time { maxProcessingTime } minutes."); } // container group is still working, restart this sub-orchestration with // the same input data context.ContinueAsNew((maximumRunDuration, aciRequirements)); // return some values if needed return(new { }); }
private static async Task <ICommandResult> ProcessCommandAsync(IDurableOrchestrationContext orchestrationContext, Input functionContext, ICommandResult commandResult, ILogger log) { var commandMessage = default(ICommandMessage); var commandCallback = default(string); try { orchestrationContext.SetCustomStatus($"Acquire callback url", log); commandCallback = await orchestrationContext .CallActivityWithRetryAsync <string>(nameof(CallbackUrlGetActivity), new CallbackUrlGetActivity.Input() { InstanceId = orchestrationContext.InstanceId, Command = functionContext.Command }) .ConfigureAwait(true); commandMessage = new ProviderCommandMessage(functionContext.Command, commandCallback); if (!(functionContext.Command is ProviderRegisterCommand) && !functionContext.Provider.Registered.HasValue) { log.LogInformation($"Register provider {functionContext.Provider.Id} for command {functionContext.Command.CommandId}"); await orchestrationContext .RegisterProviderAsync(functionContext.Provider, true) .ConfigureAwait(true); } if (!string.IsNullOrEmpty(functionContext.Command.ProjectId) && functionContext.Provider.PrincipalId.HasValue) { log.LogInformation($"Enable provider {functionContext.Provider.Id} for command {functionContext.Command.CommandId}"); await orchestrationContext .CallActivityWithRetryAsync(nameof(ProjectResourcesAccessActivity), new ProjectResourcesAccessActivity.Input() { ProjectId = functionContext.Command.ProjectId, PrincipalId = functionContext.Provider.PrincipalId.Value }) .ConfigureAwait(true); } orchestrationContext.SetCustomStatus($"Augmenting command", log); functionContext.Command = await AugmentCommandAsync(orchestrationContext, functionContext) .ConfigureAwait(true); await orchestrationContext .AuditAsync(functionContext.Command, commandResult, functionContext.Provider) .ConfigureAwait(true); try { orchestrationContext.SetCustomStatus($"Sending command", log); commandResult = await orchestrationContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandSendActivity), new CommandSendActivity.Input() { Provider = functionContext.Provider, CommandMessage = commandMessage }) .ConfigureAwait(true); } catch (RetryCanceledException) { commandResult = await orchestrationContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultFetchActivity), new CommandResultFetchActivity.Input() { Provider = functionContext.Provider, CommandMessage = commandMessage }) .ConfigureAwait(true); } finally { await orchestrationContext .AuditAsync(functionContext.Command, commandResult, functionContext.Provider) .ConfigureAwait(true); } if (!commandResult.RuntimeStatus.IsFinal()) { var commandTimeout = (commandResult.Timeout > TimeSpan.Zero && commandResult.Timeout < CommandResult.MaximumTimeout) ? commandResult.Timeout // use the timeout reported back by the provider : CommandResult.MaximumTimeout; // use the defined maximum timeout orchestrationContext.SetCustomStatus($"Waiting for command result", log); commandResult = await orchestrationContext .WaitForExternalEvent <ICommandResult>(functionContext.Command.CommandId.ToString(), commandTimeout, null) .ConfigureAwait(true); if (commandResult is null) { // provider ran into a timeout // lets give our provider a last // chance to return a command result commandResult = await orchestrationContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultFetchActivity), new CommandResultFetchActivity.Input() { Provider = functionContext.Provider, CommandMessage = commandMessage }) .ConfigureAwait(true); if (commandResult.RuntimeStatus.IsActive()) { // the last change result still doesn't report a final runtime status // escalate the timeout by throwing an appropriate exception throw new TimeoutException($"Provider '{functionContext.Provider.Id}' ran into timeout ({commandTimeout})"); } } } } catch (Exception exc) { orchestrationContext.SetCustomStatus($"Sending command failed: {exc.Message}", log, exc); commandResult ??= functionContext.Command.CreateResult(); commandResult.Errors.Add(exc.AsSerializable()); } finally { await orchestrationContext .AuditAsync(functionContext.Command, commandResult, functionContext.Provider) .ConfigureAwait(true); await ProcessOutputAsync(orchestrationContext, functionContext.Provider, functionContext.Command, commandResult) .ConfigureAwait(true); } return(commandResult); }
public virtual async Task <Status> RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { string entLookup; try { var actionArgs = context.GetInput <ExecuteActionArguments>(); entLookup = actionArgs.StateDetails.EnterpriseLookup; } catch { entLookup = context.GetInput <string>(); } if (!context.IsReplaying) { log.LogInformation($"ValidatePointQueryLimits"); } var genericRetryOptions = new RetryOptions(TimeSpan.FromSeconds(1), 3) { BackoffCoefficient = 1.5, Handle = handleRetryException }; var status = Status.Initialized; var entsWithLicense = await context.CallActivityWithRetryAsync <List <string> >( "ValidatePointQueryLimitsOrchestration_FindEnterprisesWithForecastLicense", genericRetryOptions, entLookup); var invalidEnts = new List <Tuple <string, Status> >(); if (!entsWithLicense.IsNullOrEmpty()) { // if (!context.IsReplaying) // log.LogInformation($"...: {stateCtxt.ToJSON()}"); var entValidateTasks = entsWithLicense.Select(entLookup => { return(context.CallActivityWithRetryAsync <Tuple <string, Status> >( "ValidatePointQueryLimitsOrchestration_ValidateEnterprisesForecastPointQueries", genericRetryOptions, entLookup)); }).ToList(); invalidEnts = (await Task.WhenAll(entValidateTasks)).Where(s => !s.Item2).ToList(); } // else if (!context.IsReplaying) // log.LogError($"...: {stateCtxt.ToJSON()}"); if (invalidEnts.Any()) { // if (!context.IsReplaying) // log.LogInformation($"...: {stateCtxt.ToJSON()}"); var revokeTasks = invalidEnts.Select(invalidEnt => { return(context.CallActivityWithRetryAsync <Status>("ValidatePointQueryLimitsOrchestration_RevokeEnterpriseForecastLicense", genericRetryOptions, invalidEnt.Item1)); }).ToList(); var revokeStati = await Task.WhenAll(revokeTasks); status = revokeStati.All(rs => rs) ? Status.Success : Status.GeneralError.Clone("Not all licenses properly revoked"); if (!status) { status.Metadata["RevokeStati"] = revokeStati.JSONConvert <JArray>(); } } // else if (!context.IsReplaying) // log.LogError($"...: {stateCtxt.ToJSON()}"); return(status); }
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var(provider, command) = functionContext .GetInput <(ProviderDocument, ProviderRegisterCommand)>(); try { if (command is null) { // no command was given !!! // restart the orchestration // with a new command instance. functionContext.SetCustomStatus("Creating command", log); var systemUser = await functionContext .CallActivityWithRetryAsync <UserDocument>(nameof(TeamCloudSystemUserActivity), null) .ConfigureAwait(true); var providerCommand = new ProviderRegisterCommand ( systemUser.PopulateExternalModel(), new ProviderConfiguration() ); functionContext .ContinueAsNew((provider, providerCommand)); } else if (provider is null) { // no provider was given !!! // fan out registration with // one orchestration per provider. var providers = await functionContext .ListProvidersAsync() .ConfigureAwait(true); if (providers.Any()) { functionContext.SetCustomStatus($"Register provider/s", log); var tasks = providers .Select(provider => functionContext.CallSubOrchestratorWithRetryAsync(nameof(ProviderRegisterOrchestration), (provider, command))); await Task .WhenAll(tasks) .ConfigureAwait(true); } } else { command.Payload .TeamCloudApplicationInsightsKey = await functionContext .GetInstrumentationKeyAsync() .ConfigureAwait(true); command.Payload .Properties = provider.Properties; functionContext.SetCustomStatus($"Sending command", log); var commandResult = await functionContext .SendProviderCommandAsync <ProviderRegisterCommand, ProviderRegisterCommandResult>(command, provider) .ConfigureAwait(true); using (await functionContext.LockContainerDocumentAsync(provider).ConfigureAwait(true)) { provider = await functionContext .GetProviderAsync(provider.Id) .ConfigureAwait(true); if (provider is null) { log.LogWarning($"Provider '{provider.Id}' registration skipped - provider no longer exists"); } else { provider.PrincipalId = commandResult.Result.PrincipalId; provider.CommandMode = commandResult.Result.CommandMode; provider.Registered = functionContext.CurrentUtcDateTime; provider.ResourceProviders = commandResult.Result.ResourceProviders; provider.Properties = provider.Properties.Override(commandResult.Result.Properties); functionContext.SetCustomStatus($"Updating provider", log); provider = await functionContext .SetProviderAsync(provider) .ConfigureAwait(true); if (provider.PrincipalId.HasValue) { functionContext.SetCustomStatus($"Resolving provider identity", log); var providerUser = await functionContext .GetUserAsync(provider.PrincipalId.Value.ToString(), allowUnsafe : true) .ConfigureAwait(true); if (providerUser is null) { providerUser = new UserDocument { Id = provider.PrincipalId.Value.ToString(), Role = TeamCloudUserRole.Provider, UserType = UserType.Provider }; functionContext.SetCustomStatus($"Granting provider access", log); _ = await functionContext .SetUserTeamCloudInfoAsync(providerUser, allowUnsafe : true) .ConfigureAwait(true); } } } } functionContext.SetCustomStatus($"Provider registered", log); } } catch (Exception exc) { if (provider != null) { functionContext.SetCustomStatus($"Failed to register provider '{provider.Id}' - {exc.Message}", log, exc); } else if (command != null) { functionContext.SetCustomStatus($"Failed to register providers - {exc.Message}", log, exc); } else { functionContext.SetCustomStatus($"Failed to initiate provider registration - {exc.Message}", log, exc); } } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var exportRequiredData = context.GetInput <ExportDataRequirement>(); var sentNotificationDataEntity = exportRequiredData.NotificationDataEntity; var exportDataEntity = exportRequiredData.ExportDataEntity; if (!context.IsReplaying) { log.LogInformation($"Start to export the notification {sentNotificationDataEntity.Id}!"); } try { if (!context.IsReplaying) { log.LogInformation("About to update export is in progress."); } exportDataEntity.Status = ExportStatus.InProgress.ToString(); await context.CallActivityWithRetryAsync( FunctionNames.UpdateExportDataActivity, FunctionSettings.DefaultRetryOptions, exportDataEntity); if (!context.IsReplaying) { log.LogInformation("About to get the metadata information."); } var metaData = await context.CallActivityWithRetryAsync <Metadata>( FunctionNames.GetMetadataActivity, FunctionSettings.DefaultRetryOptions, (sentNotificationDataEntity, exportDataEntity)); if (!context.IsReplaying) { log.LogInformation("About to start file upload."); } await context.CallActivityWithRetryAsync( FunctionNames.UploadActivity, FunctionSettings.DefaultRetryOptions, (sentNotificationDataEntity, metaData, exportDataEntity.FileName)); if (!context.IsReplaying) { log.LogInformation("About to send file card."); } var consentId = await context.CallActivityWithRetryAsync <string>( FunctionNames.SendFileCardActivity, FunctionSettings.DefaultRetryOptions, (exportRequiredData.UserId, exportRequiredData.NotificationDataEntity.Id, exportDataEntity.FileName)); if (!context.IsReplaying) { log.LogInformation("About to update export is completed."); } exportDataEntity.FileConsentId = consentId; exportDataEntity.Status = ExportStatus.Completed.ToString(); await context.CallActivityWithRetryAsync( FunctionNames.UpdateExportDataActivity, FunctionSettings.DefaultRetryOptions, exportDataEntity); log.LogInformation($"ExportOrchestration is successful for notification id:{sentNotificationDataEntity.Id}!"); } catch (Exception ex) { log.LogError(ex, $"Failed to export notification {sentNotificationDataEntity.Id} : {ex.Message}"); await context.CallActivityWithRetryAsync( FunctionNames.HandleExportFailureActivity, FunctionSettings.DefaultRetryOptions, exportDataEntity); } }
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } (string operationActivityName, object operationActivityInput, string operationInstanceId) = functionContext.GetInput <(string, object, string)>(); var operationLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { if (string.IsNullOrEmpty(operationInstanceId)) { operationInstanceId = await functionContext .CallActivityWithRetryAsync <string>(operationActivityName, operationActivityInput) .ConfigureAwait(true); if (!string.IsNullOrEmpty(operationInstanceId)) { operationLog.LogInformation($"Azure DevOps Operation '{operationInstanceId}' started"); functionContext.ContinueAsNew((operationActivityName, operationActivityInput, operationInstanceId)); } } else { await functionContext .CreateTimer(functionContext.CurrentUtcDateTime.AddSeconds(10), CancellationToken.None) .ConfigureAwait(true); var status = await functionContext .CallActivityWithRetryAsync <OperationStatus>(nameof(OperationStatusActivity), operationInstanceId) .ConfigureAwait(true); if (status.IsProgressStatus()) { operationLog.LogInformation($"Azure DevOps Operation '{operationInstanceId}' in progress"); functionContext .ContinueAsNew((operationActivityName, operationActivityInput, operationInstanceId)); } else if (status.IsErrorStatus()) { var operationError = await functionContext .CallActivityWithRetryAsync <string>(nameof(OperationErrorActivity), operationInstanceId) .ConfigureAwait(false); operationLog.LogWarning($"Azure DevOps Operation '{operationInstanceId}' failed: {operationError ?? "Unknown error"}"); if (string.IsNullOrEmpty(operationError)) { throw new Exception($"Operation '{operationInstanceId}' failed"); } else { throw new Exception(operationError); } } else { operationLog.LogInformation($"Azure DevOps Operation '{operationInstanceId}' succeeded"); } } } catch (Exception exc) { operationLog.LogError(exc, $"Orchestration '{nameof(OperationOrchestration)}' failed: {exc.Message}"); throw exc.AsSerializable(); } }
private async Task CallAsyncWithActivity(IDurableOrchestrationContext context, int maxNumberOfAttempts) { var retryOptions = new RetryOptions(TimeSpan.FromSeconds(5), maxNumberOfAttempts); await context.CallActivityWithRetryAsync(nameof(ActivityWithRetryAsync), retryOptions, context.GetInput <string>()); }
private async Task PassingNonSerializableModel(IDurableOrchestrationContext context, int maxNumberOfAttempts) { var retryOptions = new RetryOptions(TimeSpan.FromSeconds(5), maxNumberOfAttempts); await context.CallActivityWithRetryAsync(nameof(ActivityWithRetryAsyncNonSerializable), retryOptions, new MemoryStream(100)); }
public static Task <TeamCloudInstance> GetTeamCloudAsync(this IDurableOrchestrationContext durableOrchestrationContext) { return(durableOrchestrationContext .CallActivityWithRetryAsync <TeamCloudInstance>(nameof(TeamCloudGetActivity), null)); }
public static Task <UserDocument> GetUserAsync(this IDurableOrchestrationContext functionContext, string userId, bool allowUnsafe = false) => functionContext.IsLockedBy <UserDocument>(userId) || allowUnsafe ? functionContext.CallActivityWithRetryAsync <UserDocument>(nameof(UserGetActivity), userId) : throw new NotSupportedException($"Unable to get user '{userId}' without acquired lock");
public static Task <UserDocument> SetUserProjectMembershipAsync(this IDurableOrchestrationContext functionContext, UserDocument user, string projectId, bool allowUnsafe = false) => functionContext.IsLockedBy <UserDocument>(user.Id) || allowUnsafe ? functionContext.CallActivityWithRetryAsync <UserDocument>(nameof(UserProjectMembershipSetActivity), (user, projectId)) : throw new NotSupportedException($"Unable to create or update project membership without acquired lock for user {user.Id}");
public static Task <IEnumerable <ProviderDocument> > ListProvidersAsync(this IDurableOrchestrationContext durableOrchestrationContext, bool includeServiceProviders = false) => durableOrchestrationContext.CallActivityWithRetryAsync <IEnumerable <ProviderDocument> >(nameof(ProviderListActivity), includeServiceProviders);
public static Task SetAppSettingAsync(this IDurableOrchestrationContext functionContext, string key, string value = default) => functionContext.CallActivityWithRetryAsync(nameof(ProviderCommandAppSettingActivity), (key, value));
public static Task <Project> CreateProjectAsync(this IDurableOrchestrationContext functionContext, Project project) => functionContext.CallActivityWithRetryAsync <Project>(nameof(ProjectCreateActivity), project);
public override async Task <ICommandResult> HandleAsync(ComponentTaskRunCommand command, IAsyncCollector <ICommand> commandQueue, IDurableOrchestrationContext orchestrationContext, ILogger log) { if (command is null) { throw new ArgumentNullException(nameof(command)); } if (commandQueue is null) { throw new ArgumentNullException(nameof(commandQueue)); } if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } if (log is null) { throw new ArgumentNullException(nameof(log)); } var commandResult = command.CreateResult(); var organization = await WaitForOrganizationInitAsync(orchestrationContext, command) .ConfigureAwait(true); var project = await WaitForProjectInitAsync(orchestrationContext, command) .ConfigureAwait(true); var component = await orchestrationContext .CallActivityWithRetryAsync <Component>(nameof(ComponentGetActivity), new ComponentGetActivity.Input() { ComponentId = command.Payload.ComponentId, ProjectId = command.Payload.ProjectId }) .ConfigureAwait(true); using (await orchestrationContext.LockContainerDocumentAsync(component).ConfigureAwait(true)) { commandResult.Result = await orchestrationContext .CallActivityWithRetryAsync <ComponentTask>(nameof(ComponentTaskGetActivity), new ComponentTaskGetActivity.Input() { ComponentTaskId = command.Payload.Id, ComponentId = command.Payload.ComponentId }) .ConfigureAwait(true) ?? command.Payload; if (commandResult.Result.TaskState != TaskState.Canceled) { try { commandResult.Result = await UpdateComponentTaskAsync(orchestrationContext, commandResult.Result, TaskState.Initializing) .ConfigureAwait(true); if (!AzureResourceIdentifier.TryParse(component.IdentityId, out var _)) { // ensure every component has an identity assigned that can be used // as the identity of the task runner container to access azure or // call back into teamcloud using the azure cli extension component = await orchestrationContext .CallActivityWithRetryAsync <Component>(nameof(ComponentIdentityActivity), new ComponentIdentityActivity.Input() { Component = component }) .ConfigureAwait(true); } commandResult.Result = await UpdateComponentTaskAsync(orchestrationContext, commandResult.Result, TaskState.Processing) .ConfigureAwait(true); await(command.Payload.Type switch { ComponentTaskType.Create => ProcessCreateCommandAsync(), ComponentTaskType.Delete => ProcessDeleteCommandAsync(), ComponentTaskType.Custom => ProcessCustomCommandAsync(), _ => throw new NotSupportedException($"The command type '{command.Payload.Type}' is not supported") }).ConfigureAwait(true); commandResult.Result = await UpdateComponentTaskAsync(orchestrationContext, commandResult.Result, TaskState.Succeeded) .ConfigureAwait(true); }
public async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { await context.CallActivityWithRetryAsync(DurableFunctionNameConstants.EMAIL_SEND, new RetryOptions(TimeSpan.FromMinutes(5), 3), null); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var notificationDataEntity = context.GetInput <NotificationDataEntity>(); if (!context.IsReplaying) { log.LogInformation($"Start to prepare to send the notification {notificationDataEntity.Id}!"); } try { if (!context.IsReplaying) { log.LogInformation("About to store message content."); } await context.CallActivityWithRetryAsync( FunctionNames.StoreMessageActivity, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to sync recipients."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.SyncRecipientsOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to create conversation for recipients if required."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.TeamsConversationOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to send messages to send queue."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.SendQueueOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); log.LogInformation($"PrepareToSendOrchestrator successfully completed for notification: {notificationDataEntity.Id}!"); } catch (Exception ex) { var errorMessage = $"PrepareToSendOrchestrator failed for notification: {notificationDataEntity.Id}. Exception Message: {ex.Message}"; log.LogError(ex, errorMessage); await context.CallActivityWithRetryAsync( FunctionNames.HandleFailureActivity, FunctionSettings.DefaultRetryOptions, (notificationDataEntity, ex)); } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var notification = context.GetInput <NotificationDataEntity>(); // Update notification status. await context.CallActivityWithRetryAsync( FunctionNames.UpdateNotificationStatusActivity, FunctionSettings.DefaultRetryOptions, (notification.Id, NotificationStatus.Sending)); if (!context.IsReplaying) { log.LogInformation("About to get all recipients."); } var results = await context.CallActivityWithRetryAsync <(IEnumerable <SentNotificationDataEntity>, TableContinuationToken)>( FunctionNames.GetRecipientsActivity, FunctionSettings.DefaultRetryOptions, notification); var recipientsList = new List <SentNotificationDataEntity>(); if (results.Item1 != null) { recipientsList.AddRange(results.Item1.ToList()); } while (results.Item2 != null) { results = await context.CallActivityWithRetryAsync <(IEnumerable <SentNotificationDataEntity>, TableContinuationToken)>( FunctionNames.GetRecipientsByTokenActivity, FunctionSettings.DefaultRetryOptions, (notification.Id, results.Item2)); if (results.Item1 != null) { recipientsList.AddRange(results.Item1); } } if (!context.IsReplaying) { log.LogInformation("About to send data aggregration message to data queue."); } await context.CallActivityWithRetryAsync( FunctionNames.DataAggregationTriggerActivity, FunctionSettings.DefaultRetryOptions, (notification.Id, recipientsList.Count)); var batches = SeparateIntoBatches(recipientsList); var totalBatchCount = batches.Count; if (!context.IsReplaying) { log.LogInformation($"About to process {totalBatchCount} batches."); } var tasks = new List <Task>(); for (var batchIndex = 0; batchIndex < totalBatchCount; batchIndex++) { if (!context.IsReplaying) { log.LogInformation($"About to process batch {batchIndex + 1} / {totalBatchCount}"); } var task = context.CallActivityWithRetryAsync( FunctionNames.SendBatchMessagesActivity, FunctionSettings.DefaultRetryOptions, (notification, batches[batchIndex])); tasks.Add(task); } // Fan-out Fan-in await Task.WhenAll(tasks); }
private static async Task PerformLearnerMatch(IDurableOrchestrationContext context, ApprenticeshipIncentiveOutput incentive) { await context.CallActivityWithRetryAsync(nameof(LearnerMatchAndUpdate), new RetryOptions(TimeSpan.FromSeconds(1), 3), new LearnerMatchInput { ApprenticeshipIncentiveId = incentive.Id }); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext orchestrationContext, ILogger log) { if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } var functionInput = orchestrationContext.GetInput <Input>(); var functionLog = orchestrationContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { if (string.IsNullOrEmpty(functionInput.DeploymentResourceId)) { orchestrationContext.SetCustomStatus($"Starting deployment using activity '{functionInput.DeploymentActivityName}'", functionLog); functionInput.DeploymentResourceId = await orchestrationContext .CallActivityWithRetryAsync <string>(functionInput.DeploymentActivityName, functionInput.DeploymentActivityInput) .ConfigureAwait(true); if (!string.IsNullOrEmpty(functionInput.DeploymentResourceId)) { orchestrationContext.SetCustomStatus($"Monitoring deployment '{functionInput.DeploymentResourceId}'", functionLog); orchestrationContext.ContinueAsNew(functionInput); } } else { await orchestrationContext .CreateTimer(orchestrationContext.CurrentUtcDateTime.AddSeconds(10), CancellationToken.None) .ConfigureAwait(true); var state = await orchestrationContext .CallActivityWithRetryAsync <AzureDeploymentState>(nameof(AzureDeploymentStateActivity), functionInput.DeploymentResourceId) .ConfigureAwait(true); if (state.IsProgressState()) { orchestrationContext .ContinueAsNew(functionInput); } else if (state.IsErrorState()) { var errors = (await orchestrationContext .CallActivityWithRetryAsync <IEnumerable <string> >(nameof(AzureDeploymentErrorsActivity), functionInput.DeploymentResourceId) .ConfigureAwait(true)) ?? Enumerable.Empty <string>(); foreach (var error in errors) { functionLog.LogError($"Deployment '{functionInput.DeploymentResourceId}' reported error: {error}"); } throw new AzureDeploymentException($"Deployment '{functionInput.DeploymentResourceId}' failed", functionInput.DeploymentResourceId, errors.ToArray()); } else { var output = await orchestrationContext .GetDeploymentOutputAsync(functionInput.DeploymentResourceId) .ConfigureAwait(true); if (!string.IsNullOrEmpty(functionInput.DeploymentOutputEventName)) { await orchestrationContext .RaiseEventAsync(functionInput.DeploymentOwnerInstanceId, functionInput.DeploymentOutputEventName, output) .ConfigureAwait(true); } orchestrationContext.SetOutput(output); } } } catch (Exception exc) { functionLog.LogError(exc, $"Orchestration '{nameof(AzureDeploymentOrchestration)}' failed: {exc.Message}"); throw exc.AsSerializable(); } }
public static Task <IEnumerable <Project> > ListProjectsAsync(this IDurableOrchestrationContext durableOrchestrationContext) => durableOrchestrationContext.CallActivityWithRetryAsync <IEnumerable <Project> >(nameof(ProjectListActivity), null);
public static Task <TeamCloudInstanceDocument> GetTeamCloudAsync(this IDurableOrchestrationContext durableOrchestrationContext) => durableOrchestrationContext.CallActivityWithRetryAsync <TeamCloudInstanceDocument>(nameof(TeamCloudGetActivity), null);
private static async Task <OrchestratorProjectCreateCommandResult> ProvisionAsync(IDurableOrchestrationContext orchestrationContext, OrchestratorProjectCreateCommand command, ILogger log) { var teamCloud = await orchestrationContext .GetTeamCloudAsync() .ConfigureAwait(true); var commandResult = command.CreateResult(); var project = commandResult.Result = command.Payload; project.Tags = teamCloud.Tags.Override(project.Tags); var projectUsers = project.Users.ToList(); var providers = await orchestrationContext .ListProvidersAsync(project.Type.Providers.Select(p => p.Id).ToList()) .ConfigureAwait(true); var providerUserTasks = providers .Where(p => p.PrincipalId.HasValue) .Select(p => orchestrationContext.GetUserAsync(p.PrincipalId.Value.ToString(), allowUnsafe: true)); var providerUsers = await Task.WhenAll(providerUserTasks) .ConfigureAwait(true); foreach (var u in providerUsers) { u.EnsureProjectMembership(project.Id, ProjectUserRole.Provider); } projectUsers.AddRange(providerUsers); using (await orchestrationContext.LockContainerDocumentAsync(project).ConfigureAwait(true)) { orchestrationContext.SetCustomStatus($"Creating project", log); project = commandResult.Result = await orchestrationContext .CreateProjectAsync(project) .ConfigureAwait(true); orchestrationContext.SetCustomStatus($"Adding users", log); project.Users = await Task .WhenAll(projectUsers.Select(user => orchestrationContext.SetUserProjectMembershipAsync(user, project.Id, allowUnsafe: true))) .ConfigureAwait(true); } orchestrationContext.SetCustomStatus($"Allocating subscription", log); var subscriptionId = await orchestrationContext .CallActivityWithRetryAsync <Guid>(nameof(ProjectSubscriptionSelectActivity), project) .ConfigureAwait(true); orchestrationContext.SetCustomStatus($"Initializing subscription", log); await orchestrationContext .InitializeSubscriptionAsync(subscriptionId, waitFor : false) .ConfigureAwait(true); orchestrationContext.SetCustomStatus($"Provisioning resources", log); var deploymentOutput = await orchestrationContext .CallDeploymentAsync(nameof(ProjectResourcesCreateActivity), new ProjectResourcesCreateActivity.Input() { Project = project, SubscriptionId = subscriptionId }) .ConfigureAwait(true); using (await orchestrationContext.LockContainerDocumentAsync(project).ConfigureAwait(true)) { project.ResourceGroup = new AzureResourceGroup() { SubscriptionId = subscriptionId, Region = project.Type.Region, Id = (string)deploymentOutput.GetValueOrDefault("resourceGroupId", default(string)), Name = (string)deploymentOutput.GetValueOrDefault("resourceGroupName", default(string)) }; orchestrationContext.SetCustomStatus($"Provisioning identity", log); project.Identity = await orchestrationContext .CallActivityWithRetryAsync <ProjectIdentity>(nameof(ProjectIdentityCreateActivity), project) .ConfigureAwait(true); project = commandResult.Result = await orchestrationContext .SetProjectAsync(project) .ConfigureAwait(true); } orchestrationContext.SetCustomStatus($"Tagging resources", log); await orchestrationContext .CallActivityWithRetryAsync(nameof(ProjectResourcesTagActivity), project) .ConfigureAwait(true); orchestrationContext.SetCustomStatus($"Registering required resource providers", log); await orchestrationContext .RegisterResourceProvidersAsync(project) .ConfigureAwait(true); orchestrationContext.SetCustomStatus($"Sending provider commands", log); var providerCommand = new ProviderProjectCreateCommand ( command.User.PopulateExternalModel(), project.PopulateExternalModel(), command.CommandId ); var providerResults = await orchestrationContext .SendProviderCommandAsync <ProviderProjectCreateCommand, ProviderProjectCreateCommandResult>(providerCommand, project, failFast : true) .ConfigureAwait(true); var providerException = providerResults.Values? .SelectMany(result => result.Errors ?? new List <CommandError>()) .ToException(); if (providerException != null) { throw providerException; } return(commandResult); }
/// <summary> /// Calls an activity function with the default retry options. /// </summary> /// <typeparam name="TResult">The type for the result returned by the activity function.</typeparam> /// <param name="functionName">The name of the function to call.</param> /// <param name="input">An optional input object to send to the function.</param> /// <returns>Returns the object returned by the activity function.</returns> public static async Task <TResult> CallActivityWithDefaultRetryAsync <TResult>(this IDurableOrchestrationContext context, string functionName, object input = null) { return(await context.CallActivityWithRetryAsync <TResult>(functionName, DefaultRetryOptions, input)); }