Codeunit.run vs TryFunction to record errors and contine

samantha73
samantha73 Member Posts: 119

Hi All

I'm trying to find when one is better than the other base on use cases. For example I want create job queue to release sales orders, if one of the SO fail to release , record the error on a error log table and continue. Here i'm committing after each sales order. Is there a difference if I use TryFunction like below vs codeunit.run

trigger OnRun()
begin
ProcessAll();
end;

procedure ProcessAll()
var
SalesHeader: Record "Sales Header";
UpdatedCount: Integer;
SkippedCount: Integer;
ActivityLog: Record "Activity Log";
begin
SalesHeader.Reset();
SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
SalesHeader.SetRange(Status, SalesHeader.Status::Open);


if not SalesHeader.FindSet(true) then
exit;

repeat
ClearLastError(); // important so GetLastErrorText() is scoped to this record

if TrySetPendingPrepayment(SalesHeader) then begin
UpdatedCount += 1;
LogActivity(SalesHeader.RecordId, ActivityLog.Status::Success,
'SETSTATUS', 'Order status set',
StrSubstNo('Status set to %1 for %2.',
SalesHeader.Status, SalesHeader."No."));
end else begin
SkippedCount += 1;
LogActivity(SalesHeader.RecordId, ActivityLog.Status::Failed,
'SETSTATUS', 'Order status not set',
StrSubstNo('Error processing %1: %2',
SalesHeader."No.", GetLastErrorText()));
end;
Commit();
until SalesHeader.Next() = 0;

end;

[TryFunction]
local procedure TrySetPendingPrepayment(var SalesHeader: Record "Sales Header")
begin
if SalesHeader.Status <> SalesHeader.Status::Open then
exit;

SalesHeader.Validate(Status, SalesHeader.Status::"Pending Prepayment");
end;

local procedure LogActivity(ContextRecordID: RecordId; Status: Option Success,Warning,Failed,Canceled,Information,Completed; Context: Text[30]; Description: Text[250]; Message: Text)
var
ActivityLog: Record "Activity Log";
begin
ActivityLog.LogActivity(ContextRecordID, Status, Context, Description, Message);
end;

Comments

  • jeffreybulanadi
    jeffreybulanadi Member Posts: 6

    I believe you misunderstood the use of TryFunction Return Value

    if TrySetPendingPrepayment(...) then, but TryFunction procedures do not return Boolean values. Instead, they succeed silently or fail and return control to the caller.

    So, this line:

    if TrySetPendingPrepayment(SalesHeader) then
    …will always evaluate to true, because the function doesn't return anything. The correct pattern is:

    al
    if not TrySetPendingPrepayment(SalesHeader) then
    // Error occurred
    else
    // Success
    Fix: Flip the logic, check for failure, not success.

    Let’s learn without the yawns. Follow me. https://www.linkedin.com/in/jeffreybulanadi

    https://learnbeyondbc.com

  • joostheger
    joostheger Member Posts: 21
    edited 2025-10-23

    Sorry, but this is not true.

    See for example: https://yzhums.com/19630/

    I have this code, and it workes, proven by unit tests, in either the success or the failure.

       if TrySendRequest(CreateRequestJson(ArInCutOrder), OutputLocation) then begin
    ArinResult.RequestOutputsLocation := Format(OutputLocation);
    ArinResult.Status := ArinResult.Status::Sent;
    ArinResult.Modify(true);
    Sent := true;
    exit;
    end
    else begin
    ArinResult.Error := Format(GetLastErrorText(), -2024);
    ArinResult.Status := ArinResult.Status::Error;
    ArinResult.Modify(true);
    Message(StrSubstNo(ErrorMessageLbl, ArinResult.Error));
    exit;
    end; [TryFunction]
    local procedure TrySendRequest(RequestJsonObject: JsonObject; var OutputLocation: Text)
  • joostheger
    joostheger Member Posts: 21

    @Samantha73, I dont see why codeunit.run would be beneficial in logging errors. Using a try function like you're demonstrating seems at first glance as the right move.