This commit is contained in:
2026-09-20 20:40:21 +08:00
parent 088c219c20
commit 2213647db4
4 changed files with 55 additions and 4 deletions
@@ -3,6 +3,15 @@ const OPTIONS = { scenario: 'phase3-loading-hard-gate-finalize', deploymentBlock
function id(value) { return value == null ? '' : String(value) }
function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) }
export async function replayCompletedCommand(send, recordTransportFailure) {
const first = await send()
if (first.http !== 0) return first
// Used only after authoritative COMPLETED + operation history have been read.
// The closure retains the exact original body and idempotency key.
recordTransportFailure(first)
return send()
}
function evidenceSignature(data) {
return JSON.stringify((data?.evidences || []).map((item) => ({
id: id(item?.id), type: item?.evidenceType || null, fileId: id(item?.fileId),
@@ -268,8 +277,12 @@ export async function run(context) {
&& id(concurrentCompleteOperations[0]?.operatorId) && Boolean(concurrentCompleteOperations[0]?.createdAt)
&& completion.task?.taskStatus === 'COMPLETED' && completion.task?.workflowStatus === 'COMPLETED'
const completeResponse = completion.task?.taskStatus === 'COMPLETED'
? await request(context, 'POST', `${taskPath}/complete`, completeBody,
{ 'Idempotency-Key': completeKey })
? await replayCompletedCommand(() => request(context, 'POST', `${taskPath}/complete`, completeBody,
{ 'Idempotency-Key': completeKey }), failed => {
context.createdResources.loadingCompleteReplayTransportFailures ??= []
context.createdResources.loadingCompleteReplayTransportFailures.push({ taskId,
operationId: completeBody.operationId, http: failed.http, error: failed.raw || 'transport failure' })
})
: acceptedCompleteResponse
context.assert(MODULE, '两个不同幂等键并发 complete 仅一成功且只写一条完成审计',
completeResponse, concurrentCompleteVerified,