diff --git a/community/knowledge/performance/httpclient-inside-write-transaction-holds-locks.good.al b/community/knowledge/performance/httpclient-inside-write-transaction-holds-locks.good.al index 218f22c..ea490fe 100644 --- a/community/knowledge/performance/httpclient-inside-write-transaction-holds-locks.good.al +++ b/community/knowledge/performance/httpclient-inside-write-transaction-holds-locks.good.al @@ -5,22 +5,21 @@ codeunit 50100 "HttpClient Holds Locks Good" begin Customer."Search Name" := Customer.Name; Customer.Modify(false); - TaskScheduler.CreateTask(Codeunit::"Customer Sync Task", 0, true, CompanyName(), CurrentDateTime()); + // RecordId binds the task to this specific customer; the platform loads it into Rec on OnRun. + TaskScheduler.CreateTask(Codeunit::"Customer Sync Task", 0, true, CompanyName(), CurrentDateTime(), Customer.RecordId); end; } codeunit 50101 "Customer Sync Task" { + TableNo = Customer; + trigger OnRun() var Client: HttpClient; - Customer: Record Customer; Response: HttpResponseMessage; begin - // Separate session: no write-transaction lock is held during the HTTP call. - if Customer.FindSet() then - repeat - Client.Get(StrSubstNo('https://example.local/sync/%1', Customer."No."), Response); - until Customer.Next() = 0; + // Separate session: Rec is the single customer passed via RecordId; no write-transaction lock is held. + Client.Get(StrSubstNo('https://example.local/sync/%1', Rec."No."), Response); end; } diff --git a/community/knowledge/performance/oncompanyopen-subscribers-must-not-do-io.good.al b/community/knowledge/performance/oncompanyopen-subscribers-must-not-do-io.good.al index 8938140..d1b3aa5 100644 --- a/community/knowledge/performance/oncompanyopen-subscribers-must-not-do-io.good.al +++ b/community/knowledge/performance/oncompanyopen-subscribers-must-not-do-io.good.al @@ -2,17 +2,22 @@ codeunit 50100 "Login Subscriber IO Good" { [EventSubscriber(ObjectType::Codeunit, Codeunit::"System Initialization", OnAfterLogin, '', false, false)] local procedure OnAfterLogin() + var + TaskId: Guid; + StoredId: Text; begin // Guard to interactive sessions only; background task sessions also raise OnAfterLogin. - if not (Session.GetCurrentClientType() in [ClientType::Web, ClientType::Windows, ClientType::Desktop, ClientType::Tablet, ClientType::Phone]) then + if not (Session.CurrentClientType() in [ClientType::Web, ClientType::Windows, ClientType::Desktop, ClientType::Tablet, ClientType::Phone]) then exit; - // Idempotent: skip if a task for this codeunit is already queued. - if TaskScheduler.TaskExists(Codeunit::"Login Subscriber IO Work") then - exit; + // Idempotent: TaskExists requires the GUID returned by CreateTask, stored across logins. + if IsolatedStorage.Get('LoginSyncTaskId', DataScope::Company, StoredId) then + if Evaluate(TaskId, StoredId) then + if TaskScheduler.TaskExists(TaskId) then + exit; - // Defer the I/O work; CreateTask is the only write allowed on this path. - TaskScheduler.CreateTask(Codeunit::"Login Subscriber IO Work", 0, true, CompanyName(), CurrentDateTime() + 60000); + TaskId := TaskScheduler.CreateTask(Codeunit::"Login Subscriber IO Work", 0, true, CompanyName(), CurrentDateTime() + 60000); + IsolatedStorage.Set('LoginSyncTaskId', Format(TaskId), DataScope::Company); end; }