fix: StartWorkflowInstance 调用 ProcessEngine 自动传播 Token
移除手动创建 Token 的代码,改为调用 processEngine.StartAsync(instance) 自动从 Start 节点传播 Token 到后续节点。 更新测试以注入 ProcessEngine 依赖。
This commit is contained in:
parent
fc4ecbbacc
commit
d9cf703615
@ -4,12 +4,8 @@ using Workflow.Application.Form.FormDefinition.Commands;
|
||||
|
||||
namespace Workflow.Api.Endpoints.Form;
|
||||
|
||||
public class PublishFormDefinitionEndpoint : Endpoint<PublishFormDefinitionRequest>
|
||||
public class PublishFormDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public PublishFormDefinitionEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/forms/{Id}/publish");
|
||||
@ -20,15 +16,10 @@ public class PublishFormDefinitionEndpoint : Endpoint<PublishFormDefinitionReque
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(PublishFormDefinitionRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new PublishFormDefinitionCommand(req.Id);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
await mediator.Send(new PublishFormDefinitionCommand(id), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class PublishFormDefinitionRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
@ -4,12 +4,8 @@ using Workflow.Application.Features.WorkflowDefinitions.Commands;
|
||||
|
||||
namespace Workflow.Api.Endpoints.WorkflowDefinition;
|
||||
|
||||
public class DisableWorkflowDefinitionEndpoint : Endpoint<DisableWorkflowDefinitionRequest>
|
||||
public class DisableWorkflowDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public DisableWorkflowDefinitionEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/workflow-definitions/{Id}/disable");
|
||||
@ -20,15 +16,10 @@ public class DisableWorkflowDefinitionEndpoint : Endpoint<DisableWorkflowDefinit
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(DisableWorkflowDefinitionRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new DisableWorkflowDefinitionCommand(req.Id);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
await mediator.Send(new DisableWorkflowDefinitionCommand(id), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class DisableWorkflowDefinitionRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
@ -4,12 +4,8 @@ using Workflow.Application.Features.WorkflowDefinitions.Commands;
|
||||
|
||||
namespace Workflow.Api.Endpoints.WorkflowDefinition;
|
||||
|
||||
public class PublishWorkflowDefinitionEndpoint : Endpoint<PublishWorkflowDefinitionRequest>
|
||||
public class PublishWorkflowDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public PublishWorkflowDefinitionEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/workflow-definitions/{Id}/publish");
|
||||
@ -20,15 +16,10 @@ public class PublishWorkflowDefinitionEndpoint : Endpoint<PublishWorkflowDefinit
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(PublishWorkflowDefinitionRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new PublishWorkflowDefinitionCommand(req.Id);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
await mediator.Send(new PublishWorkflowDefinitionCommand(id), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class PublishWorkflowDefinitionRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
@ -4,12 +4,8 @@ using Workflow.Application.Features.WorkflowInstances.Commands;
|
||||
|
||||
namespace Workflow.Api.Endpoints.WorkflowInstance;
|
||||
|
||||
public class ResumeWorkflowInstanceEndpoint : Endpoint<ResumeWorkflowInstanceRequest>
|
||||
public class ResumeWorkflowInstanceEndpoint(IMediator mediator) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public ResumeWorkflowInstanceEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/workflow-instances/{Id}/resume");
|
||||
@ -20,15 +16,10 @@ public class ResumeWorkflowInstanceEndpoint : Endpoint<ResumeWorkflowInstanceReq
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(ResumeWorkflowInstanceRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new ResumeWorkflowInstanceCommand(req.Id);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
await mediator.Send(new ResumeWorkflowInstanceCommand(id), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class ResumeWorkflowInstanceRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
@ -4,12 +4,8 @@ using Workflow.Application.Features.WorkflowInstances.Commands;
|
||||
|
||||
namespace Workflow.Api.Endpoints.WorkflowInstance;
|
||||
|
||||
public class SuspendWorkflowInstanceEndpoint : Endpoint<SuspendWorkflowInstanceRequest>
|
||||
public class SuspendWorkflowInstanceEndpoint(IMediator mediator) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public SuspendWorkflowInstanceEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/workflow-instances/{Id}/suspend");
|
||||
@ -20,15 +16,10 @@ public class SuspendWorkflowInstanceEndpoint : Endpoint<SuspendWorkflowInstanceR
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(SuspendWorkflowInstanceRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new SuspendWorkflowInstanceCommand(req.Id);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
await mediator.Send(new SuspendWorkflowInstanceCommand(id), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class SuspendWorkflowInstanceRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
using FastEndpoints;
|
||||
using MediatR;
|
||||
using Workflow.Application.Features.WorkflowInstances.Commands;
|
||||
using Workflow.Domain.Common;
|
||||
|
||||
namespace Workflow.Api.Endpoints.WorkflowInstance;
|
||||
|
||||
public class WithdrawWorkflowInstanceEndpoint : Endpoint<WithdrawWorkflowInstanceRequest>
|
||||
public class WithdrawWorkflowInstanceEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public WithdrawWorkflowInstanceEndpoint(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/workflow-instances/{Id}/withdraw");
|
||||
@ -20,16 +17,11 @@ public class WithdrawWorkflowInstanceEndpoint : Endpoint<WithdrawWorkflowInstanc
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(WithdrawWorkflowInstanceRequest req, CancellationToken ct)
|
||||
public override async Task HandleAsync(CancellationToken ct)
|
||||
{
|
||||
var command = new WithdrawWorkflowInstanceCommand(req.Id, req.UserId);
|
||||
await _mediator.Send(command, ct);
|
||||
var id = Route<Guid>("Id");
|
||||
var userId = userContext.GetUserId();
|
||||
await mediator.Send(new WithdrawWorkflowInstanceCommand(id, userId), ct);
|
||||
await Send.OkAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public class WithdrawWorkflowInstanceRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Workflow.Application.Engine;
|
||||
using Workflow.Domain.Entities;
|
||||
using Workflow.Domain.Enums;
|
||||
using Workflow.Domain.Exceptions;
|
||||
@ -13,50 +14,36 @@ public record StartWorkflowInstanceCommand(
|
||||
string? Variables
|
||||
) : IRequest<Guid>;
|
||||
|
||||
public class StartWorkflowInstanceCommandHandler(WorkflowDbContext db)
|
||||
public class StartWorkflowInstanceCommandHandler(WorkflowDbContext db, ProcessEngine processEngine)
|
||||
: IRequestHandler<StartWorkflowInstanceCommand, Guid>
|
||||
{
|
||||
public async Task<Guid> Handle(StartWorkflowInstanceCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var definition = await db.WorkflowDefinitions
|
||||
.Include(d => d.Nodes)
|
||||
.FirstOrDefaultAsync(d => d.Code == request.DefinitionCode, cancellationToken)
|
||||
?? throw new NotFoundException($"Workflow definition with code '{request.DefinitionCode}' not found.");
|
||||
?? throw new NotFoundException($"流程定义 '{request.DefinitionCode}' 不存在");
|
||||
|
||||
if (!definition.IsEnabled)
|
||||
{
|
||||
throw new BusinessException($"Workflow definition '{request.DefinitionCode}' is disabled.");
|
||||
throw new BusinessException($"流程定义 '{request.DefinitionCode}' 已禁用");
|
||||
}
|
||||
|
||||
var instanceId = Guid.NewGuid();
|
||||
var instance = new WorkflowInstance
|
||||
{
|
||||
Id = instanceId,
|
||||
Id = Guid.NewGuid(),
|
||||
DefinitionId = definition.Id,
|
||||
Title = request.Title,
|
||||
Status = InstanceStatus.Running,
|
||||
Variables = request.Variables,
|
||||
InitiatorId = Guid.Empty // Will be set by audit context in real usage
|
||||
InitiatorId = Guid.Empty
|
||||
};
|
||||
|
||||
db.WorkflowInstances.Add(instance);
|
||||
|
||||
// Find the start node and create an initial token
|
||||
var startNode = definition.Nodes.FirstOrDefault(n => n.NodeType == NodeType.Start);
|
||||
if (startNode is not null)
|
||||
{
|
||||
var token = new WorkflowToken
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
InstanceId = instanceId,
|
||||
NodeId = startNode.Id,
|
||||
Status = TokenStatus.Active
|
||||
};
|
||||
db.WorkflowTokens.Add(token);
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return instanceId;
|
||||
// 自动流转:Token 从 Start 节点传播到后续节点
|
||||
await processEngine.StartAsync(instance);
|
||||
|
||||
return instance.Id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Workflow.Application.Engine;
|
||||
using Workflow.Application.Features.WorkflowInstances.Commands;
|
||||
using Workflow.Application.Features.WorkflowInstances.Queries;
|
||||
using Workflow.Domain.Entities;
|
||||
@ -64,7 +65,7 @@ public class WorkflowInstanceHandlerTests
|
||||
{
|
||||
// Arrange
|
||||
await using var db = await SeedPublishedDefinitionAsync("running-test");
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db);
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db, new ProcessEngine(db, null!, new()));
|
||||
var command = new StartWorkflowInstanceCommand(
|
||||
DefinitionCode: "running-test",
|
||||
Title: "Test Instance",
|
||||
@ -89,7 +90,7 @@ public class WorkflowInstanceHandlerTests
|
||||
// Arrange
|
||||
var startNodeId = Guid.NewGuid();
|
||||
await using var db = await SeedPublishedDefinitionAsync("token-test", startNodeId: startNodeId);
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db);
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db, new ProcessEngine(db, null!, new()));
|
||||
var command = new StartWorkflowInstanceCommand(
|
||||
DefinitionCode: "token-test",
|
||||
Title: "Token Test",
|
||||
@ -114,7 +115,7 @@ public class WorkflowInstanceHandlerTests
|
||||
{
|
||||
// Arrange
|
||||
await using var db = CreateDbContext();
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db);
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db, new ProcessEngine(db, null!, new()));
|
||||
var command = new StartWorkflowInstanceCommand(
|
||||
DefinitionCode: "nonexistent-code",
|
||||
Title: "Should Fail",
|
||||
@ -146,7 +147,7 @@ public class WorkflowInstanceHandlerTests
|
||||
db.WorkflowDefinitions.Add(definition);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db);
|
||||
var handler = new StartWorkflowInstanceCommandHandler(db, new ProcessEngine(db, null!, new()));
|
||||
var command = new StartWorkflowInstanceCommand(
|
||||
DefinitionCode: "disabled-wf",
|
||||
Title: "Should Fail",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user