bcquality/custom/knowledge/integration/deduplicate-inbound-messages-with-an-idempotency-check.bad.al
Tharanga Chandrasekara 07140e2223 Add new action skills for AL testing and documentation
- Introduced `al-test-writer` to generate AL test codeunits for production objects based on TDD principles.
- Added `al-userguide-test-writer` to create test codeunits from user guide steps, mapping actions and assertions.
- Implemented `bc-extension-test-guide` to generate a comprehensive TEST_GUIDE.md for Business Central extensions, covering various categories.
- Created `bc-webclient-runner` to automate UI testing of the Business Central web client, capturing screenshots and asserting UI states.
- Developed `page-scripting-e2e` to produce a recording plan for Page Scripting, ensuring a structured approach to browser-level testing.
2026-06-07 12:26:47 +12:00

33 lines
1.7 KiB
AL

// Anti-pattern: insert on every call with no idempotency check, keyed on a brand-new GUID.
// A retried or re-fetched delivery is processed again as a fresh message, so a duplicating
// source produces duplicate documents and double-applied side effects.
codeunit 50142 "Inbound Dedup Bad"
{
procedure Stage(ExternalRef: Text[100]; MsgType: Code[40]; Payload: Text): Guid
var
IntegrationMessage: Record "Integration Message";
begin
// BAD: no SetRange on External Reference + Type, no Get, no lookup of any kind.
// The source system's stable id is captured on the row but never used to detect a repeat.
IntegrationMessage.Init();
// BAD: the only "identity" is a fresh GUID. If anyone later "dedups" on Message ID,
// it can never match, because every insert mints a new one. This is the illusion of a
// dedup key that can never actually fire.
IntegrationMessage."Message ID" := CreateGuid();
IntegrationMessage.Direction := IntegrationMessage.Direction::Inbound;
IntegrationMessage."External Reference" := ExternalRef;
IntegrationMessage.Type := MsgType;
IntegrationMessage.Status := IntegrationMessage.Status::New;
IntegrationMessage.SetRequest(Payload);
// When the source RETRIES (a webhook that did not see our ack, a restart re-send, an
// overlapping poll window): this runs again with the same ExternalRef and stages a
// second message. Downstream it becomes a second sales order and a second posting.
// The duplicate volume scales with how aggressively the source retries.
IntegrationMessage.Insert(true);
exit(IntegrationMessage."Message ID");
end;
}