fix(domain): correlate withdrawal by process instance to the subscribed execution (refs #12)
All checks were successful
CI / lint (pull_request) Successful in 1m15s
CI / build (pull_request) Successful in 1m1s
CI / unit (pull_request) Successful in 1m20s
CI / frontend (pull_request) Successful in 2m50s
CI / mutation (pull_request) Successful in 5m22s
CI / verify-stack (pull_request) Successful in 7m18s
All checks were successful
CI / lint (pull_request) Successful in 1m15s
CI / build (pull_request) Successful in 1m1s
CI / unit (pull_request) Successful in 1m20s
CI / frontend (pull_request) Successful in 2m50s
CI / mutation (pull_request) Successful in 5m22s
CI / verify-stack (pull_request) Successful in 7m18s
verify-stack surfaced a Flowable 500: delivering messageEventReceived to the Beoordelen task's execution is wrong — a message boundary event's subscription lives on its own execution. Correlate instead by the registration's process instance id (recorded at submit): query the execution subscribed to RegistratieIngetrokken and deliver the message there. Withdrawal moves from IUserTaskClient to IWorkflowClient.WithdrawProcessAsync; the handler no longer needs a task lookup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -158,14 +158,13 @@ public class FlowableWorkflowClientTests
|
||||
var capture = new RequestCapture();
|
||||
var client = Client(capture.Responds(HttpStatusCode.OK,
|
||||
$$"""
|
||||
{"data":[{"id":"task-1","executionId":"exec-1","variables":[{"name":"registrationId","type":"string","value":"{{rid}}"}]}],"total":1}
|
||||
{"data":[{"id":"task-1","variables":[{"name":"registrationId","type":"string","value":"{{rid}}"}]}],"total":1}
|
||||
"""));
|
||||
|
||||
var tasks = await client.GetOpenBeoordelingenAsync();
|
||||
|
||||
var task = Assert.Single(tasks);
|
||||
Assert.Equal("task-1", task.TaskId);
|
||||
Assert.Equal("exec-1", task.ExecutionId);
|
||||
Assert.Equal(rid, task.RegistrationId);
|
||||
Assert.Equal(HttpMethod.Post, capture.Seen!.Method);
|
||||
Assert.Equal("http://flowable/flowable-rest/service/query/tasks",
|
||||
@@ -244,29 +243,58 @@ public class FlowableWorkflowClientTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Withdraw_beoordeling_delivers_the_message_to_the_task_execution()
|
||||
public async Task Withdraw_process_correlates_the_message_to_the_subscribed_execution()
|
||||
{
|
||||
var capture = new RequestCapture();
|
||||
var client = Client(capture.Responds(HttpStatusCode.OK));
|
||||
HttpRequestMessage? getReq = null;
|
||||
HttpRequestMessage? putReq = null;
|
||||
string? putBody = null;
|
||||
var client = Client(new StubHandler(async req =>
|
||||
{
|
||||
if (req.Method == HttpMethod.Get)
|
||||
{
|
||||
getReq = req;
|
||||
return new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent("""{"data":[{"id":"exec-9"}]}""", Encoding.UTF8, "application/json"),
|
||||
};
|
||||
}
|
||||
putReq = req;
|
||||
putBody = await req.Content!.ReadAsStringAsync();
|
||||
return new HttpResponseMessage(HttpStatusCode.OK);
|
||||
}));
|
||||
|
||||
await client.WithdrawBeoordelingAsync("exec-1");
|
||||
await client.WithdrawProcessAsync("pi-1");
|
||||
|
||||
// A PUT messageEventReceived on the execution trips the Beoordelen boundary event (ADR-0014).
|
||||
Assert.Equal(HttpMethod.Put, capture.Seen!.Method);
|
||||
Assert.Equal("http://flowable/flowable-rest/service/runtime/executions/exec-1",
|
||||
capture.Seen.RequestUri!.ToString());
|
||||
Assert.Equal("rest-admin:test", DecodeBasic(capture.Seen));
|
||||
Assert.Contains("\"action\":\"messageEventReceived\"", capture.Body);
|
||||
Assert.Contains("\"messageName\":\"RegistratieIngetrokken\"", capture.Body);
|
||||
// 1. Find the execution subscribed to the withdrawal message for this instance.
|
||||
Assert.Equal(HttpMethod.Get, getReq!.Method);
|
||||
Assert.Contains("service/runtime/executions", getReq.RequestUri!.ToString());
|
||||
Assert.Contains("messageEventSubscriptionName=RegistratieIngetrokken", getReq.RequestUri!.Query);
|
||||
Assert.Contains("processInstanceId=pi-1", getReq.RequestUri!.Query);
|
||||
// 2. Deliver messageEventReceived to that execution (PUT), tripping the interrupting event.
|
||||
Assert.Equal(HttpMethod.Put, putReq!.Method);
|
||||
Assert.Equal("http://flowable/flowable-rest/service/runtime/executions/exec-9",
|
||||
putReq.RequestUri!.ToString());
|
||||
Assert.Contains("\"action\":\"messageEventReceived\"", putBody);
|
||||
Assert.Contains("\"messageName\":\"RegistratieIngetrokken\"", putBody);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Withdraw_beoordeling_throws_when_flowable_rejects_the_request()
|
||||
public async Task Withdraw_process_is_a_no_op_when_no_execution_is_subscribed()
|
||||
{
|
||||
var capture = new RequestCapture();
|
||||
var client = Client(capture.Responds(HttpStatusCode.InternalServerError));
|
||||
var methods = new List<HttpMethod>();
|
||||
var client = Client(new StubHandler(req =>
|
||||
{
|
||||
methods.Add(req.Method);
|
||||
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new StringContent("""{"data":[]}""", Encoding.UTF8, "application/json"),
|
||||
});
|
||||
}));
|
||||
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => client.WithdrawBeoordelingAsync("exec-1"));
|
||||
await client.WithdrawProcessAsync("pi-1");
|
||||
|
||||
// No subscribed execution → no message delivered (best-effort), no throw.
|
||||
Assert.DoesNotContain(HttpMethod.Put, methods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user