Add StellaOps.Workflow engine: 14 libraries, WebService, 8 test projects
Extract product-agnostic workflow engine from Ablera.Serdica.Workflow into standalone StellaOps.Workflow.* libraries targeting net10.0. Libraries (14): - Contracts, Abstractions (compiler, decompiler, expression runtime) - Engine (execution, signaling, scheduling, projections, hosted services) - ElkSharp (generic graph layout algorithm) - Renderer.ElkSharp, Renderer.ElkJs, Renderer.Msagl, Renderer.Svg - Signaling.Redis, Signaling.OracleAq - DataStore.MongoDB, DataStore.PostgreSQL, DataStore.Oracle WebService: ASP.NET Core Minimal API with 22 endpoints Tests (8 projects, 109 tests pass): - Engine.Tests (105 pass), WebService.Tests (4 E2E pass) - Renderer.Tests, DataStore.MongoDB/Oracle/PostgreSQL.Tests - Signaling.Redis.Tests, IntegrationTests.Shared Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,436 @@
|
||||
using System;
|
||||
|
||||
using StellaOps.Workflow.Abstractions;
|
||||
using StellaOps.Workflow.Contracts;
|
||||
using StellaOps.Workflow.Engine.Exceptions;
|
||||
using StellaOps.Workflow.Engine.Services;
|
||||
|
||||
namespace StellaOps.Workflow.WebService.Endpoints;
|
||||
|
||||
internal static class WorkflowEndpoints
|
||||
{
|
||||
public static RouteGroupBuilder MapWorkflowEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/workflow");
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Workflow runtime
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapPost("/start", StartWorkflow);
|
||||
group.MapGet("/instances/{id}", GetInstance);
|
||||
group.MapGet("/instances", GetInstances);
|
||||
group.MapGet("/tasks/{id}", GetTask);
|
||||
group.MapGet("/tasks", GetTasks);
|
||||
group.MapPost("/tasks/{id}/complete", CompleteTask);
|
||||
group.MapPost("/tasks/{id}/assign", AssignTask);
|
||||
group.MapPost("/tasks/{id}/release", ReleaseTask);
|
||||
group.MapPost("/signals/raise", RaiseSignal);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Definition query (in-memory catalog)
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/definitions", GetDefinitions);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Definition deployment (store-backed)
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/definitions/{id}", GetDefinitionById);
|
||||
group.MapPost("/definitions/import", ImportDefinition);
|
||||
group.MapPost("/definitions/export", ExportDefinition);
|
||||
group.MapGet("/definitions/{name}/versions", GetDefinitionVersions);
|
||||
group.MapPost("/definitions/{name}/activate", ActivateDefinition);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Diagrams
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/diagrams/{name}", GetDiagram);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Canonical schema & validation
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/canonical/schema", GetCanonicalSchema);
|
||||
group.MapPost("/canonical/validate", ValidateCanonical);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Operational: functions, metadata, retention
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/functions", GetFunctionCatalog);
|
||||
group.MapGet("/metadata", GetServiceMetadata);
|
||||
group.MapPost("/retention/run", RunRetention);
|
||||
|
||||
// ────────────────────────────────────────────────────
|
||||
// Signals: dead letters & pump telemetry
|
||||
// ────────────────────────────────────────────────────
|
||||
group.MapGet("/signals/dead-letters", GetDeadLetters);
|
||||
group.MapPost("/signals/dead-letters/replay", ReplayDeadLetters);
|
||||
group.MapGet("/signals/pump/stats", GetSignalPumpStats);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Runtime handlers
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static async Task<IResult> StartWorkflow(
|
||||
StartWorkflowRequest request,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await runtimeService.StartWorkflowAsync(request, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
catch (BaseResultException ex)
|
||||
{
|
||||
return Results.BadRequest(new { error = ex.MessageId, message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetInstance(
|
||||
string id,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
string? actorId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.GetInstanceAsync(new WorkflowInstanceGetRequest
|
||||
{
|
||||
WorkflowInstanceId = id,
|
||||
ActorId = actorId,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetInstances(
|
||||
WorkflowRuntimeService runtimeService,
|
||||
string? workflowName,
|
||||
string? workflowVersion,
|
||||
string? workflowInstanceId,
|
||||
string? businessReferenceKey,
|
||||
string? status,
|
||||
bool? includeDetails,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.GetInstancesAsync(new WorkflowInstancesGetRequest
|
||||
{
|
||||
WorkflowName = workflowName,
|
||||
WorkflowVersion = workflowVersion,
|
||||
WorkflowInstanceId = workflowInstanceId,
|
||||
BusinessReferenceKey = businessReferenceKey,
|
||||
Status = status,
|
||||
IncludeDetails = includeDetails ?? false,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetTask(
|
||||
string id,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
string? actorId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.GetTaskAsync(new WorkflowTaskGetRequest
|
||||
{
|
||||
WorkflowTaskId = id,
|
||||
ActorId = actorId,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetTasks(
|
||||
WorkflowRuntimeService runtimeService,
|
||||
string? workflowName,
|
||||
string? workflowVersion,
|
||||
string? workflowInstanceId,
|
||||
string? businessReferenceKey,
|
||||
string? assignee,
|
||||
string? status,
|
||||
string? actorId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.GetTasksAsync(new WorkflowTasksGetRequest
|
||||
{
|
||||
WorkflowName = workflowName,
|
||||
WorkflowVersion = workflowVersion,
|
||||
WorkflowInstanceId = workflowInstanceId,
|
||||
BusinessReferenceKey = businessReferenceKey,
|
||||
Assignee = assignee,
|
||||
Status = status,
|
||||
ActorId = actorId,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> CompleteTask(
|
||||
string id,
|
||||
WorkflowTaskCompleteRequest request,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.CompleteTaskAsync(request with
|
||||
{
|
||||
WorkflowTaskId = id,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> AssignTask(
|
||||
string id,
|
||||
WorkflowTaskAssignRequest request,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.AssignTaskAsync(request with
|
||||
{
|
||||
WorkflowTaskId = id,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ReleaseTask(
|
||||
string id,
|
||||
WorkflowTaskReleaseRequest request,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.ReleaseTaskAsync(request with
|
||||
{
|
||||
WorkflowTaskId = id,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> RaiseSignal(
|
||||
WorkflowSignalRaiseRequest request,
|
||||
WorkflowRuntimeService runtimeService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await runtimeService.RaiseExternalSignalAsync(request, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Definition query handlers (in-memory catalog)
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static IResult GetDefinitions(
|
||||
IWorkflowDefinitionCatalog definitionCatalog,
|
||||
string? workflowName,
|
||||
string? workflowVersion)
|
||||
{
|
||||
var definitions = definitionCatalog.GetDefinitions().AsEnumerable();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(workflowName))
|
||||
{
|
||||
definitions = definitions.Where(x =>
|
||||
string.Equals(x.WorkflowName, workflowName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(workflowVersion))
|
||||
{
|
||||
definitions = definitions.Where(x =>
|
||||
string.Equals(x.WorkflowVersion, workflowVersion, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
return Results.Ok(new WorkflowDefinitionGetResponse
|
||||
{
|
||||
Definitions = definitions.ToArray(),
|
||||
});
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Definition deployment handlers (store-backed)
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static async Task<IResult> GetDefinitionById(
|
||||
string id,
|
||||
WorkflowDefinitionDeploymentService deploymentService,
|
||||
bool? includeRendering,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deploymentService.GetDefinitionByIdAsync(new WorkflowDefinitionByIdRequest
|
||||
{
|
||||
WorkflowName = id,
|
||||
IncludeRendering = includeRendering ?? false,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ImportDefinition(
|
||||
WorkflowDefinitionImportRequest request,
|
||||
WorkflowDefinitionDeploymentService deploymentService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deploymentService.ImportAsync(request, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ExportDefinition(
|
||||
WorkflowDefinitionExportRequest request,
|
||||
WorkflowDefinitionDeploymentService deploymentService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deploymentService.ExportAsync(request, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetDefinitionVersions(
|
||||
string name,
|
||||
WorkflowDefinitionDeploymentService deploymentService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deploymentService.GetVersionsAsync(new WorkflowDefinitionVersionsGetRequest
|
||||
{
|
||||
WorkflowName = name,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ActivateDefinition(
|
||||
string name,
|
||||
WorkflowDefinitionActivateRequest request,
|
||||
WorkflowDefinitionDeploymentService deploymentService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deploymentService.ActivateAsync(request with
|
||||
{
|
||||
WorkflowName = name,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Diagram handlers
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static async Task<IResult> GetDiagram(
|
||||
string name,
|
||||
WorkflowDiagramService diagramService,
|
||||
string? workflowVersion,
|
||||
string? workflowInstanceId,
|
||||
string? layoutProvider,
|
||||
string? layoutEffort,
|
||||
int? layoutOrderingIterations,
|
||||
int? layoutPlacementIterations,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await diagramService.GetDiagramAsync(new WorkflowDiagramGetRequest
|
||||
{
|
||||
WorkflowName = name,
|
||||
WorkflowVersion = workflowVersion,
|
||||
WorkflowInstanceId = workflowInstanceId,
|
||||
LayoutProvider = layoutProvider,
|
||||
LayoutEffort = layoutEffort,
|
||||
LayoutOrderingIterations = layoutOrderingIterations,
|
||||
LayoutPlacementIterations = layoutPlacementIterations,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Canonical schema & validation handlers
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static IResult GetCanonicalSchema(
|
||||
WorkflowCanonicalDefinitionService canonicalService)
|
||||
{
|
||||
var response = canonicalService.GetSchema();
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static IResult ValidateCanonical(
|
||||
WorkflowCanonicalValidateRequest request,
|
||||
WorkflowCanonicalDefinitionService canonicalService)
|
||||
{
|
||||
var response = canonicalService.Validate(request);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Operational handlers
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static IResult GetFunctionCatalog(
|
||||
WorkflowFunctionCatalogService functionCatalogService)
|
||||
{
|
||||
var response = functionCatalogService.GetCatalog();
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static IResult GetServiceMetadata()
|
||||
{
|
||||
var response = new WorkflowServiceMetadataGetResponse
|
||||
{
|
||||
Metadata = new WorkflowServiceMetadata
|
||||
{
|
||||
ServiceName = "StellaOps.Workflow.WebService",
|
||||
DiagramProvider = "ElkSharp",
|
||||
SupportsDefinitionInspection = true,
|
||||
SupportsInstanceInspection = true,
|
||||
SupportsCanonicalSchemaInspection = true,
|
||||
SupportsCanonicalImportValidation = true,
|
||||
},
|
||||
};
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> RunRetention(
|
||||
WorkflowRetentionRunRequest request,
|
||||
WorkflowRetentionService retentionService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await retentionService.RunAsync(request.ReferenceUtc, cancellationToken);
|
||||
var response = new WorkflowRetentionRunResponse
|
||||
{
|
||||
ExecutedOnUtc = DateTime.UtcNow,
|
||||
StaleInstancesMarked = result.StaleInstancesMarked,
|
||||
StaleTasksMarked = result.StaleTasksMarked,
|
||||
PurgedInstances = result.PurgedInstances,
|
||||
PurgedTasks = result.PurgedTasks,
|
||||
PurgedTaskEvents = result.PurgedTaskEvents,
|
||||
PurgedRuntimeStates = result.PurgedRuntimeStates,
|
||||
};
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════
|
||||
// Signal dead-letter & pump telemetry handlers
|
||||
// ════════════════════════════════════════════════════════
|
||||
|
||||
private static async Task<IResult> GetDeadLetters(
|
||||
WorkflowSignalDeadLetterService deadLetterService,
|
||||
string? signalId,
|
||||
string? workflowInstanceId,
|
||||
string? signalType,
|
||||
int? maxMessages,
|
||||
bool? includeRawPayload,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deadLetterService.GetMessagesAsync(new WorkflowSignalDeadLettersGetRequest
|
||||
{
|
||||
SignalId = signalId,
|
||||
WorkflowInstanceId = workflowInstanceId,
|
||||
SignalType = signalType,
|
||||
MaxMessages = maxMessages ?? 50,
|
||||
IncludeRawPayload = includeRawPayload ?? false,
|
||||
}, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ReplayDeadLetters(
|
||||
WorkflowSignalDeadLetterReplayRequest request,
|
||||
WorkflowSignalDeadLetterService deadLetterService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await deadLetterService.ReplayAsync(request, cancellationToken);
|
||||
return Results.Ok(response);
|
||||
}
|
||||
|
||||
private static IResult GetSignalPumpStats(
|
||||
WorkflowSignalPumpTelemetryService telemetryService)
|
||||
{
|
||||
var response = telemetryService.GetStats();
|
||||
return Results.Ok(response);
|
||||
}
|
||||
}
|
||||
35
src/Workflow/StellaOps.Workflow.WebService/Program.cs
Normal file
35
src/Workflow/StellaOps.Workflow.WebService/Program.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using StellaOps.Workflow.DataStore.MongoDB;
|
||||
using StellaOps.Workflow.Engine.Authorization;
|
||||
using StellaOps.Workflow.Engine.Services;
|
||||
using StellaOps.Workflow.Signaling.Redis;
|
||||
using StellaOps.Workflow.WebService.Endpoints;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Core workflow engine services (runtime, definitions, signals, rendering, etc.)
|
||||
builder.Services.AddWorkflowEngineCoreServices(builder.Configuration);
|
||||
|
||||
// Workflow engine hosted services (signal pump, retention background jobs)
|
||||
builder.Services.AddWorkflowEngineHostedServices();
|
||||
|
||||
// Authorization service (required by WorkflowRuntimeService)
|
||||
builder.Services.AddScoped<WorkflowTaskAuthorizationService>();
|
||||
|
||||
// MongoDB data store (projection store, runtime state, signals, dead letters, etc.)
|
||||
builder.Services.AddWorkflowMongoDataStore(builder.Configuration);
|
||||
|
||||
// Redis signaling driver (wake notifications across instances)
|
||||
builder.Services.AddWorkflowRedisSignaling(builder.Configuration);
|
||||
|
||||
// Rendering layout engines can be registered here when available:
|
||||
// builder.Services.AddWorkflowElkSharpRenderer();
|
||||
// builder.Services.AddWorkflowSvgRenderer();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Map all workflow API endpoints under /api/workflow
|
||||
app.MapWorkflowEndpoints();
|
||||
|
||||
await app.RunAsync();
|
||||
|
||||
public partial class Program { }
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"StellaOps.Workflow.Host": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:49940;http://localhost:49941"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Engine/StellaOps.Workflow.Engine.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Abstractions/StellaOps.Workflow.Abstractions.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Contracts/StellaOps.Workflow.Contracts.csproj" />
|
||||
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.DataStore.Oracle/StellaOps.Workflow.DataStore.Oracle.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.DataStore.MongoDB/StellaOps.Workflow.DataStore.MongoDB.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Signaling.Redis/StellaOps.Workflow.Signaling.Redis.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Renderer.Svg/StellaOps.Workflow.Renderer.Svg.csproj" />
|
||||
<ProjectReference Include="../__Libraries/StellaOps.Workflow.Renderer.ElkSharp/StellaOps.Workflow.Renderer.ElkSharp.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.ElkSharp/StellaOps.ElkSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
33
src/Workflow/StellaOps.Workflow.WebService/appsettings.json
Normal file
33
src/Workflow/StellaOps.Workflow.WebService/appsettings.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{ "Name": "Console" }
|
||||
]
|
||||
},
|
||||
"WorkflowBackend": {
|
||||
"Provider": "Mongo",
|
||||
"Mongo": {
|
||||
"ConnectionStringName": "WorkflowMongo",
|
||||
"DatabaseName": "stellaops_workflow"
|
||||
}
|
||||
},
|
||||
"WorkflowSignalDriver": {
|
||||
"Provider": "Native"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"WorkflowMongo": "mongodb://localhost:27017"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user