private string GetFullPath(WorkflowStorageContext context, string key) { var containerPath = GetContainerPath(context); var activityId = context.ActivityId; return($"${containerPath}/{activityId}/{key}.dat"); }
private async Task AddActivityOutputAsync(Engine engine, ActivityExecutionContext activityExecutionContext, CancellationToken cancellationToken) { var workflowExecutionContext = activityExecutionContext.WorkflowExecutionContext; var workflowInstance = activityExecutionContext.WorkflowInstance; var workflowBlueprint = workflowExecutionContext.WorkflowBlueprint; var activities = new Dictionary <string, object>(); foreach (var activity in workflowBlueprint.Activities.Where(x => !string.IsNullOrWhiteSpace(x.Name))) { var activityType = await _activityTypeService.GetActivityTypeAsync(activity.Type, cancellationToken); var activityDescriptor = await _activityTypeService.DescribeActivityType(activityType, cancellationToken); var outputProperties = activityDescriptor.OutputProperties; var storageProviderLookup = activity.PropertyStorageProviders; var activityModel = new Dictionary <string, object?>(); var storageContext = new WorkflowStorageContext(workflowInstance, activity.Id); foreach (var property in outputProperties) { var propertyName = property.Name; var storageProviderName = storageProviderLookup.GetItem(propertyName) ?? property.DefaultWorkflowStorageProvider; activityModel[propertyName] = (Func <object?>)(() => _workflowStorageService.LoadAsync(storageProviderName, storageContext, propertyName, cancellationToken).Result); } activities[activity.Name !] = activityModel;
public override ValueTask DeleteAsync(WorkflowStorageContext context, CancellationToken cancellationToken = default) { var workflowInstanceId = context.WorkflowInstance.Id; _cacheSignal.TriggerToken(GetSignalKey(workflowInstanceId)); return(new ValueTask()); }
public override ValueTask DeleteAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var state = GetData(context); state.Remove(key); return(new ValueTask()); }
public virtual async Task <RunWorkflowResult> RunWorkflowAsync( IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, string?activityId = default, WorkflowInput?input = default, CancellationToken cancellationToken = default) { using var loggingScope = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id }); using var workflowExecutionScope = _serviceScopeFactory.CreateScope(); if (input?.Input != null) { var workflowStorageContext = new WorkflowStorageContext(workflowInstance, workflowBlueprint.Id); var inputStorageProvider = _workflowStorageService.GetProviderByNameOrDefault(input.StorageProviderName); await inputStorageProvider.SaveAsync(workflowStorageContext, nameof(WorkflowInstance.Input), input.Input, cancellationToken); workflowInstance.Input = new WorkflowInputReference(inputStorageProvider.Name); await _mediator.Publish(new WorkflowInputUpdated(workflowInstance), cancellationToken); } var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input?.Input); var result = await RunWorkflowInternalAsync(workflowExecutionContext, activityId, cancellationToken); await workflowExecutionContext.WorkflowExecutionLog.FlushAsync(cancellationToken); return(result); }
private async ValueTask ApplyStoredObjectValuesAsync(ActivityExecutionContext context, object activity, CancellationToken cancellationToken, string parentName = null) { var properties = activity.GetType().GetProperties().Where(IsActivityProperty).ToList(); var nestedProperties = activity.GetType().GetProperties().Where(IsActivityObjectProperty).ToList(); var propertyStorageProviderDictionary = context.ActivityBlueprint.PropertyStorageProviders; var workflowStorageContext = new WorkflowStorageContext(context.WorkflowInstance, context.ActivityId); foreach (var property in properties) { var propertyName = parentName == null ? property.Name : $"{parentName}_{property.Name}"; var attr = property.GetCustomAttribute <ActivityPropertyAttributeBase>(); var providerName = propertyStorageProviderDictionary.GetItem(propertyName) ?? attr.DefaultWorkflowStorageProvider; var value = await _workflowStorageService.LoadAsync(providerName, workflowStorageContext, propertyName, cancellationToken); if (value != null) { var typedValue = value.ConvertTo(property.PropertyType); property.SetValue(activity, typedValue); } } foreach (var nestedProperty in nestedProperties) { var instance = Activator.CreateInstance(nestedProperty.PropertyType); var propertyName = parentName == null ? nestedProperty.Name : $"{parentName}_{nestedProperty.Name}"; await ApplyStoredObjectValuesAsync(context, instance, cancellationToken, propertyName); } }
public async ValueTask <WorkflowInputReference> SaveAsync(WorkflowInput input, WorkflowInstance workflowInstance, CancellationToken cancellationToken = default) { var workflowStorageContext = new WorkflowStorageContext(workflowInstance, workflowInstance.DefinitionId); var inputStorageProvider = GetProviderByNameOrDefault(input.StorageProviderName); await inputStorageProvider.SaveAsync(workflowStorageContext, nameof(WorkflowInstance.Input), input.Input, cancellationToken); return(new WorkflowInputReference(inputStorageProvider.Name)); }
public override ValueTask DeleteAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var workflowInstanceId = context.WorkflowInstance.Id; var activityId = context.ActivityId; var cacheKey = GetKey(workflowInstanceId, activityId, key); _cache.Remove(cacheKey); return(new ValueTask()); }
public override ValueTask <object?> LoadAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var workflowInstanceId = context.WorkflowInstance.Id; var activityId = context.ActivityId; var cacheKey = GetKey(workflowInstanceId, activityId, key); var value = _cache.TryGetValue(cacheKey, out var v) ? v : default; return(new ValueTask <object?>(value)); }
public override ValueTask SaveAsync(WorkflowStorageContext context, string key, object?value, CancellationToken cancellationToken = default) { var workflowInstanceId = context.WorkflowInstance.Id; var activityId = context.ActivityId; var cacheKey = GetKey(workflowInstanceId, activityId, key); var options = new MemoryCacheEntryOptions(); options.ExpirationTokens.Add(_cacheSignal.GetToken(GetSignalKey(workflowInstanceId))); _cache.Set(cacheKey, value, options); return(new ValueTask()); }
private async ValueTask StoreAppliedValuesAsync(ActivityExecutionContext context, IActivity activity, CancellationToken cancellationToken) { var properties = activity.GetType().GetProperties().Where(IsActivityProperty).ToList(); var propertyStorageProviderDictionary = context.ActivityBlueprint.PropertyStorageProviders; var workflowStorageContext = new WorkflowStorageContext(context.WorkflowInstance, context.ActivityId); foreach (var property in properties) { var value = property.GetValue(activity); var providerName = propertyStorageProviderDictionary.GetItem(property.Name); await _workflowStorageService.SaveAsync(providerName, workflowStorageContext, property.Name, value, cancellationToken); } }
public async ValueTask <FluidValue> ProcessAsync(FluidValue input, FilterArguments arguments, TemplateContext context) { var activityName = input.ToStringValue(); var activityPropertyName = arguments.Values.First().ToStringValue(); var activityExecutionContext = (ActivityExecutionContext)context.Model; var activityBlueprint = activityExecutionContext.WorkflowExecutionContext.GetActivityBlueprintByName(activityName) !; var activityId = activityBlueprint.Id; var storageProviderName = activityBlueprint.PropertyStorageProviders.GetItem(activityPropertyName); var storageContext = new WorkflowStorageContext(activityExecutionContext.WorkflowExecutionContext.WorkflowInstance, activityId); var value = await _workflowStorageService.LoadAsync(storageProviderName, storageContext, activityPropertyName); return(new ObjectValue(value)); }
public async ValueTask <object?> LoadAsync(WorkflowInstance workflowInstance, CancellationToken cancellationToken = default) { var inputReference = workflowInstance.Input; if (inputReference == null) { return(null); } var context = new WorkflowStorageContext(workflowInstance, workflowInstance.DefinitionId); return(await LoadAsync(inputReference.ProviderName, context, nameof(WorkflowInstance.Input), cancellationToken)); }
private async Task SavePropertyAsync(ActivityExecutionContext context, string propertyName, object?value, CancellationToken cancellationToken) { var propertyStorageProviderDictionary = context.ActivityBlueprint.PropertyStorageProviders; var providerName = propertyStorageProviderDictionary.GetItem(propertyName); var workflowStorageContext = new WorkflowStorageContext(context.WorkflowInstance, context.ActivityId); await _workflowStorageService.SaveAsync(providerName, workflowStorageContext, propertyName, value, cancellationToken); // By convention, properties named "Output" will be stored as the workflow output. if (propertyName == "Output") { context.WorkflowInstance.Output = new WorkflowOutputReference(providerName, context.ActivityId); } }
private async ValueTask ApplyStoredValuesAsync(ActivityExecutionContext context, IActivity activity, CancellationToken cancellationToken) { var properties = activity.GetType().GetProperties().Where(IsActivityProperty).ToList(); var propertyStorageProviderDictionary = context.ActivityBlueprint.PropertyStorageProviders; var workflowStorageContext = new WorkflowStorageContext(context.WorkflowInstance, context.ActivityId); foreach (var property in properties) { var providerName = propertyStorageProviderDictionary.GetItem(property.Name); var value = await _workflowStorageService.LoadAsync(providerName, workflowStorageContext, property.Name, cancellationToken); if (value != null) { var typedValue = value.ConvertTo(property.PropertyType); property.SetValue(activity, typedValue); } } }
public override async ValueTask <object?> LoadAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var path = GetFullPath(context, key); if (!await _blobStorage.ExistsAsync(path, cancellationToken)) { return(null); } var blob = await _blobStorage.GetBlobAsync(path, cancellationToken); var contentType = blob.Metadata.GetItem("ContentType") ?? "Json"; if (contentType == "Json") { var json = await _blobStorage.ReadTextAsync(path, cancellationToken : cancellationToken); return(JsonConvert.DeserializeObject(json, _serializerSettings)); } return(await _blobStorage.ReadBytesAsync(path, cancellationToken)); }
public override async ValueTask SaveAsync(WorkflowStorageContext context, string key, object?value, CancellationToken cancellationToken = default) { if (value == null) { return; } var path = GetFullPath(context, key); if (value is Stream stream) { await _blobStorage.WriteAsync(path, stream, cancellationToken : cancellationToken); var blob = await _blobStorage.GetBlobAsync(path, cancellationToken); blob.Metadata["ContentType"] = "Binary"; await _blobStorage.SetBlobAsync(blob, cancellationToken); } else if (value is byte[] bytes) { await _blobStorage.WriteAsync(path, bytes, cancellationToken : cancellationToken); var blob = await _blobStorage.GetBlobAsync(path, cancellationToken); blob.Metadata["ContentType"] = "Binary"; await _blobStorage.SetBlobAsync(blob, cancellationToken); } else { var json = JsonConvert.SerializeObject(value, _serializerSettings); var jsonBytes = Encoding.UTF8.GetBytes(json); await _blobStorage.WriteAsync(path, jsonBytes, cancellationToken : cancellationToken); var blob = await _blobStorage.GetBlobAsync(path, cancellationToken); blob.Metadata["ContentType"] = "Json"; await _blobStorage.SetBlobAsync(blob, cancellationToken); } }
public async ValueTask <object?> LoadAsync(string?providerName, WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var provider = GetProviderByNameOrDefault(providerName); return(await provider.LoadAsync(context, key, cancellationToken)); }
public async ValueTask SaveAsync(string?providerName, WorkflowStorageContext context, string key, object?value, CancellationToken cancellationToken = default) { var provider = GetProviderByNameOrDefault(providerName); await provider.SaveAsync(context, key, value, cancellationToken); }
public virtual async Task <RunWorkflowResult> RunWorkflowAsync( IWorkflowBlueprint workflowBlueprint, WorkflowInstance workflowInstance, string?activityId = default, WorkflowInput?input = default, CancellationToken cancellationToken = default) { using var loggingScope = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id }); using var workflowExecutionScope = _serviceScopeFactory.CreateScope(); if (input?.Input != null) { var workflowStorageContext = new WorkflowStorageContext(workflowInstance, workflowBlueprint.Id); var inputStorageProvider = _workflowStorageService.GetProviderByNameOrDefault(input.StorageProviderName); await inputStorageProvider.SaveAsync(workflowStorageContext, nameof(WorkflowInstance.Input), input.Input, cancellationToken); workflowInstance.Input = new WorkflowInputReference(inputStorageProvider.Name); await _mediator.Publish(new WorkflowInputUpdated(workflowInstance), cancellationToken); } var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input?.Input); if (!string.IsNullOrWhiteSpace(workflowInstance.ContextId)) { var loadContext = new LoadWorkflowContext(workflowExecutionContext); workflowExecutionContext.WorkflowContext = await _workflowContextManager.LoadContext(loadContext, cancellationToken); } // If the workflow instance has a CurrentActivity, it means the workflow instance is being retried. var currentActivity = workflowInstance.CurrentActivity; if (currentActivity != null) { activityId = currentActivity.ActivityId; } var activity = activityId != null?workflowBlueprint.GetActivity(activityId) : default; // Give application a chance to prevent workflow from executing. var validateWorkflowExecution = new ValidateWorkflowExecution(workflowExecutionContext, activity); await _mediator.Publish(validateWorkflowExecution, cancellationToken); if (!validateWorkflowExecution.CanExecuteWorkflow) { _logger.LogInformation("Workflow execution prevented for workflow {WorkflowInstanceId}", workflowInstance.Id); return(new RunWorkflowResult(workflowInstance, activityId, false)); } await _mediator.Publish(new WorkflowExecuting(workflowExecutionContext), cancellationToken); RunWorkflowResult runWorkflowResult; switch (workflowExecutionContext.Status) { case WorkflowStatus.Idle: runWorkflowResult = await BeginWorkflow(workflowExecutionContext, activity, cancellationToken); if (!runWorkflowResult.Executed) { if (workflowInstance.WorkflowStatus != WorkflowStatus.Faulted) { _logger.LogDebug("Workflow {WorkflowInstanceId} cannot begin from an idle state (perhaps it needs a specific input)", workflowInstance.Id); return(runWorkflowResult); } } break; case WorkflowStatus.Running: await RunWorkflowAsync(workflowExecutionContext, cancellationToken); runWorkflowResult = new RunWorkflowResult(workflowInstance, activityId, true); break; case WorkflowStatus.Suspended: runWorkflowResult = await ResumeWorkflowAsync(workflowExecutionContext, activity !, cancellationToken); if (!runWorkflowResult.Executed) { _logger.LogDebug("Workflow {WorkflowInstanceId} cannot be resumed from a suspended state (perhaps it needs a specific input)", workflowInstance.Id); return(runWorkflowResult); } break; default: throw new ArgumentOutOfRangeException(); } await _mediator.Publish(new WorkflowExecuted(workflowExecutionContext), cancellationToken); var statusEvent = workflowExecutionContext.Status switch { WorkflowStatus.Cancelled => new WorkflowCancelled(workflowExecutionContext), WorkflowStatus.Finished => new WorkflowCompleted(workflowExecutionContext), WorkflowStatus.Faulted => new WorkflowFaulted(workflowExecutionContext), WorkflowStatus.Suspended => new WorkflowSuspended(workflowExecutionContext), _ => default(INotification) }; if (statusEvent != null) { await _mediator.Publish(statusEvent, cancellationToken); } await _mediator.Publish(new WorkflowExecutionFinished(workflowExecutionContext), cancellationToken); return(runWorkflowResult); }
public override ValueTask DeleteAsync(WorkflowStorageContext context, CancellationToken cancellationToken = default) { context.WorkflowInstance.ActivityData.Remove(context.ActivityId !); return(new ValueTask()); }
public abstract ValueTask SaveAsync(WorkflowStorageContext context, string key, object?value, CancellationToken cancellationToken = default);
public abstract ValueTask DeleteAsync(WorkflowStorageContext context, CancellationToken cancellationToken = default);
public abstract ValueTask <object?> LoadAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default);
public override async ValueTask DeleteAsync(WorkflowStorageContext context, CancellationToken cancellationToken = default) { var path = GetContainerPath(context); await _blobStorage.DeleteAsync(path, cancellationToken); }
public override async ValueTask DeleteAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var path = GetFullPath(context, key); await _blobStorage.DeleteAsync(path, cancellationToken); }
public async ValueTask DeleteAsync(string?providerName, WorkflowStorageContext context, CancellationToken cancellationToken = default) { var provider = GetProviderByNameOrDefault(providerName); await provider.DeleteAsync(context, cancellationToken); }
private IDictionary <string, object?> GetData(WorkflowStorageContext context) => context.WorkflowInstance.ActivityData.GetItem(context.ActivityId !, () => new Dictionary <string, object?>());
private string GetContainerPath(WorkflowStorageContext context) => context.WorkflowInstance.Id;
public override ValueTask <object?> LoadAsync(WorkflowStorageContext context, string key, CancellationToken cancellationToken = default) { var value = GetState(context, key); return(new ValueTask <object?>(value)); }