Events sometimes cause a COMMIT when throwing an ERROR !

pdjpdj Member Posts: 643
I have made a simple change in NAV2017 CU7, to ensure certain fields are filled before the document can be approved. I therefore simply made a new Subscriber function listening to “Approvals Mgmt.”.OnApproveApprovalRequest(). My function then do the custom validation and gives an ERROR if something is missing.

I know this means the event has two subscribers, and that I cannot be sure that my custom code is executed before the standard subscriber code updating the Approval Entries. It is not performance critical, so I can accept that.

However, once in a while we get the error from my subscriber function, BUT the Approval Entry is updated and COMMIT’ed !!!

First thought was, that the standard subscriber function contained a COMMIT. I tried finding it using this method: https://dynamicsuser.net/nav/b/reijer/posts/aaargh-where-is-that-commit and placing a CONSISTENT(FALSE) in the standard subscriber function. But the only COMMIT, is the automatic COMMIT after both subscriber functions are executed.
Again, even with the unconditional CONSISTENT(FALSE) in the subscriber, suddenly the Approval Entry was approved! It happens very rarely, but it does happen once in a while.

Has anyone seen anything like it, or has any idea what the problem can be?
Regards
Peter

Best Answer

  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    Answer ✓
    Nope, again :)

    I didn't find anyting better, and I think that Microsoft's doc is a bit overcomplicated :)

    All you need to have is a setup function which will add your Response to the library. The setup is a subscriber to OnAddWorkflowResponsesToLibrary in codeunit 1521:
    [EventSubscriber(Codeunit,1521,OnAddWorkflowResponsesToLibrary,"",Skip)]
    PROCEDURE CreateResponsesLibrary();
    VAR
      WorkflowRespHandl: Codeunit 1521;
    BEGIN
      WorkflowRespHandl.AddResponseToLibrary('<Your response code>', DATABASE::"Purchase Header",'<response desctiption>' ,'GROUP 0'); //the 4th parameter controls workflow step parameters, the value of 'GROUP 0' shows none
    END
    

    Then you need a handler function, which is a subscriber to ExecuteResponse in codeunit 1512:
    [EventSubscriber(Codeunit,1521,OnExecuteWorkflowResponse)]
    PROCEDURE ExecuteResponse(VAR ResponseExecuted : Boolean;Variant : Variant; xVariant: Variant;ResponseWorkflowStepInstance : Record 1504);
    VAR
      WorkflowResponse : Record 1521;
    BEGIN
      IF WorkflowResponse.GET(ResponseWorkflowStepInstance."Function Name") THEN BEGIN
        CASE WorkflowResponse."Function Name" OF
          '<Your response code>':
            BEGIN
              YourCheckFunction(Variant);
              ResponseExecuted := TRUE;
            END;
          END;
      END;
    END;
    

    Your check function needs to retrieve Purchase Header from th Variant passed in the call, and do whatever is supposed to do.

    There is of course more you can add to it, define dependencies, '<Your response code>' should be a function call returing the response code, to conform with how Microsoft did theirs, but all in all this is the very basic skeleton which should work for you.

    Slawek
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03

Answers

  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    edited 2017-09-26
    Hi,

    Nope, but just want to share my experience with handling similar requirements.

    My first approach was similar to yours - subscribe to OnSendPurchaseDocForApproval and put my checking code into the handler.

    I found this a bit problematic as even If my code thrown error and stop the workflow the error message was shown after the standard confirmation message. This of course was the result of binding order - standard subscriber was fired first and then mine, just like in your case.

    I ended up creating a function adding workflow step response event, and plugged it into the purchase approval workflow. This apporach has, in my opinion a few advantages - it is clearly visible for the users thas there is a step checking validity of certain data, you can control order of checking by changing workflow configuration, and of course it can be fired selectively for some purchase approval workflows but not for others - all user configurable.

    It is still fully event-based, all encompassed in a single codeunit, no standard object modification required.

    I guess the bug like you described should be reported to Microsoft, I don't think that you can do anyting in the code to sort it aout - apart from complete redesign of your solution.

    The 'dirty' trick would be to modify standard workflow event handling codeunit and make your subscriber function to appear first before the standard subscriber to OnApproveApprovalRequest, or modify some other codeuin with lower ID and add your subscribe funtion there.

    It seems that subscribers are bound to publishers in ascending order of object ID and then in order of apperance in the code. This is my observation only, if correct it could help firing the code in the 'righ' order, but of course it goes agains all event based coding practice as you would have to modify some standard object to get it working.

    Slawek

    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
  • pdjpdj Member Posts: 643
    Nope, but just want to share my experience with handling similar requirements.
    Thank you very much. I think this could be the solution for me as well.

    I guess I will have to look closer into this guide:
    https://msdn.microsoft.com/en-us/library/mt574349(v=nav.90).aspx
    Or did you find a better guide?
    Regards
    Peter
  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    Answer ✓
    Nope, again :)

    I didn't find anyting better, and I think that Microsoft's doc is a bit overcomplicated :)

    All you need to have is a setup function which will add your Response to the library. The setup is a subscriber to OnAddWorkflowResponsesToLibrary in codeunit 1521:
    [EventSubscriber(Codeunit,1521,OnAddWorkflowResponsesToLibrary,"",Skip)]
    PROCEDURE CreateResponsesLibrary();
    VAR
      WorkflowRespHandl: Codeunit 1521;
    BEGIN
      WorkflowRespHandl.AddResponseToLibrary('<Your response code>', DATABASE::"Purchase Header",'<response desctiption>' ,'GROUP 0'); //the 4th parameter controls workflow step parameters, the value of 'GROUP 0' shows none
    END
    

    Then you need a handler function, which is a subscriber to ExecuteResponse in codeunit 1512:
    [EventSubscriber(Codeunit,1521,OnExecuteWorkflowResponse)]
    PROCEDURE ExecuteResponse(VAR ResponseExecuted : Boolean;Variant : Variant; xVariant: Variant;ResponseWorkflowStepInstance : Record 1504);
    VAR
      WorkflowResponse : Record 1521;
    BEGIN
      IF WorkflowResponse.GET(ResponseWorkflowStepInstance."Function Name") THEN BEGIN
        CASE WorkflowResponse."Function Name" OF
          '<Your response code>':
            BEGIN
              YourCheckFunction(Variant);
              ResponseExecuted := TRUE;
            END;
          END;
      END;
    END;
    

    Your check function needs to retrieve Purchase Header from th Variant passed in the call, and do whatever is supposed to do.

    There is of course more you can add to it, define dependencies, '<Your response code>' should be a function call returing the response code, to conform with how Microsoft did theirs, but all in all this is the very basic skeleton which should work for you.

    Slawek
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
  • pdjpdj Member Posts: 643
    edited 2017-09-26
    Superb!
    I'm just sorry I already flagged your first reply with Awesome :neutral: How do I now raise my review for this new reply? :blush:

    If you are going to NavTechDays in Antwerpen I'll surely get you a beer or whatever you are into. :smiley:
    Regards
    Peter
  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    I wish I could go, but not this year, I'm afraid.

    Slawek
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
  • pdjpdj Member Posts: 643
    Once again - thank you very much. Your solution works like a charm.

    However, we kept getting purchase documents in an invalid state in other situations, and ended up removing the COMMIT in Codeunit 453. This seems to have solved our problems.

    Can you see any purpose of the COMMIT? We concluded that it was safe to remove the COMMIT, and it was even an advantage to get the JobQueueEntry rolled back and thereby get rid of the notification e-mail if an error happens. The "Job Queue Error Handler" quietly exits if the JobQueueEntry has been rolled back.
    Regards
    Peter
  • Slawek_GuzekSlawek_Guzek Member Posts: 1,690
    I think that the COMMIT in EnqueueJobQueueEntry() is to make sure that the taskid returned by TASKSCHEDULER.CREATETASK gets remembered. If you roll back the changes you are loosing the taskid and cannot access / stop the background task process anymore.

    Slawek
    Slawek Guzek
    Dynamics NAV, MS SQL Server, Wherescape RED;
    PRINCE2 Practitioner - License GR657010572SG
    GDPR Certified Data Protection Officer - PECB License DPCDPO1025070-2018-03
  • pdjpdj Member Posts: 643
    I don't quite see that as a problem. The task start by trying to get the JobQueueEntry (both the "Job Queue Dispatcher" and "Job Queue Error Handler" codeunits). When they can't find that, they simply quit and the task dies.
    Regards
    Peter
Sign In or Register to comment.