NAS & Multiple Single Instance CodeUnits

FishermanFisherman Member Posts: 456
Has anyone tried to use one NAS to start multiple single-instance codeunits? I want to try it, but I'm concerned because I don't know the threading model of Navision.

For example - if I use 1 NAS to start two single-instance codeunits to receive MSMQ messages - what happens if messages are received for both codeunits at the same time?

Also, and somewhat off-topic - why does each instance of the NAS cost 1600.00? If I read right, it's only a headless client... so why is the licensing structure like this, rather than simply a flat fee for use, and one client-license for each installed NAS?

Comments

  • DenSterDenSter Member Posts: 8,307
    Because *turning on the sarcasm* according to MSFT, NAS enables a 3 tier architecture, so it is not considered to merely be a GUI-less client session *turning off the sarcasm*.

    I have not tried it, but AFAIK every instance of NAS is a single thread.
  • FishermanFisherman Member Posts: 456
    Right....

    [sarcasm]which is why I could effect the same thing by running the CodeUnit from a normal Navision Client. Wow... it all makes perfect sense now #-o [/sarcasm]
  • FishermanFisherman Member Posts: 456
    I posted a product suggestion about this on CustomerSource. Not that they'll listen, but it's kinda stupid.
  • krikikriki Member, Moderator Posts: 9,116
    Fisherman wrote:
    For example - if I use 1 NAS to start two single-instance codeunits to receive MSMQ messages - what happens if messages are received for both codeunits at the same time?
    The NAS starts both codeunits and they wait until a message arrives.
    Once one receives a message, it starts processing it (=C/AL code). If in the meanwhile the C/AL is running to process the message of the first codeunit, another message arrives for the second codeunit, nothing happens. First the code of the first codeunit must finish and then the code of the second codeunit starts.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • FishermanFisherman Member Posts: 456
    OK...so its handling of COM Events is single threaded.

    I had thought that this would be the case.

    I was hoping there was someway to deliver a message failure back to the MSMQ if the system was already busy. Maybe I'll try tracking this one down.

    I might post this as a product suggestion, too. Middle-tier solutions are usually multi-threaded, since they can be bombarded from multiple sources. They should really consider spawning a thread per single-instance codeunit that is started.
  • DenSterDenSter Member Posts: 8,307
    There was something of a NAS distributor with either one of the commerce products, but I don't remember which one and how it exactly would work. If you can't find it in the Commerce Gateway docs, check the Commerce Portal documentation on a 3.7 disc.
  • kinekine Member Posts: 12,562
    Do you know, that it is not just simple "serial" processing? I tried this example:

    Create one Single instance CU with timer, which increase global variable. Than create form, with a button. OnPush will start the CU and will do something for some time (e.g. for i:=1 to 10000 ...) After the work, read and show the value of the variable from the singleinstance CU. You will see, that the timer was counting during the for i:=1 to 1000... work. or, at least, was calling the OnTimer event and after the process ended, all the triggers were processed... :-)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • FishermanFisherman Member Posts: 456
    Are you saying that Navision will queue the events to be processed?
  • kinekine Member Posts: 12,562
    Yes, in this case, it seems like it is true... :-) there is the test, you can use...
    OBJECT Form 90000 Test
    {
      OBJECT-PROPERTIES
      {
        Date=11.12.06;
        Time=15:49:40;
        Modified=Yes;
        Version List=;
      }
      PROPERTIES
      {
        Width=8000;
        Height=8000;
      }
      CONTROLS
      {
        { 1000000000;CommandButton;1760;1320;2200;550;
                                                     CaptionML=CSY=Run;
                                                     OnPush=BEGIN
                                                              C.RUN;
                                                              Window.OPEN('Value is: #1##########');
                                                              FOR i := 1 TO 10000 DO BEGIN
                                                                Window.UPDATE(1,C.ReadValue);
                                                              END;
                                                              Window.CLOSE;
                                                            END;
                                                             }
        { 1000000001;CommandButton;1760;1980;2200;550;
                                                     CaptionML=CSY=Read Value;
                                                     OnPush=BEGIN
                                                              MESSAGE('Value is: %1',C.ReadValue);
                                                            END;
                                                             }
      }
      CODE
      {
        VAR
          C@1000000000 : Codeunit 90000;
          i@1000000001 : Integer;
          Window@1000000002 : Dialog;
    
        BEGIN
        END.
      }
    }
    
    OBJECT Codeunit 90000 Test
    {
      OBJECT-PROPERTIES
      {
        Date=11.12.06;
        Time=15:50:03;
        Modified=Yes;
        Version List=;
      }
      PROPERTIES
      {
        SingleInstance=Yes;
        OnRun=BEGIN
                IF ISCLEAR(T) THEN
                  CREATE(T);
                T.Interval := 100;
                T.Enabled := TRUE;
                I := 0;
              END;
    
      }
      CODE
      {
        VAR
          T@1000000000 : Automation "{3B311C81-140E-11D5-8B18-00D0590B4EC5} 1.0:{3B311C92-140E-11D5-8B18-00D0590B4EC5}:'Navision Timer 1.0'.Timer" WITHEVENTS;
          I@1000000001 : Integer;
    
        PROCEDURE ReadValue@1000000001() : Integer;
        BEGIN
          EXIT(I);
        END;
    
        PROCEDURE Stop@1000000000();
        BEGIN
          T.Enabled := FALSE;
        END;
    
        EVENT T@1000000000::Timer@1(Milliseconds@1000000000 : Integer);
        BEGIN
          IF I> 2147483646 THEN
            I := 0;
          I := I +1;
        END;
    
        EVENT T@1000000000::TimerError@2(ErrorString@1000000000 : Text[1024]);
        BEGIN
        END;
    
        BEGIN
        END.
      }
    }
    
    

    There are two buttons on the form - first will run the timer, do something (loop with reading the actual value from CU - still 0...). After the loop, the timer is stopped. When you press the second button, you will see, that there is some value (it is length of the loop in 0.1 second) - it means, all timer events vere fired after the first OnPush ended... :-)

    (sorry for the used variable names and direct text constants, it is just example made in two minutes and it is not example of "how to write C/AL code"... 8) )
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • Captain_DX4Captain_DX4 Member Posts: 230
    Why not simply create a separate queue for each codeunit? Then you don't need to worry about waiting for one message to process before the second begins. Or am I missing something?
    Kristopher Webb
    Microsoft Dynamics NAV Developer
  • FishermanFisherman Member Posts: 456
    That is my intention -

    I've worked with a program before, however, that used multiple message queues. The way it had been designed, if a message arrived while another one (from another queue) was being processed, processing would immediately switch to the handler for the new message.

    I need to make sure that Navision can handle the events for multiple message arrivals on different queues - that's why I'm asking about the threading model.
  • DenSterDenSter Member Posts: 8,307
    I'm pretty sure that you can start multiple single instance codeunits within one instance of NAS. I would not be surprised however, if each has a timer that waits for 10 seconds, that the actual timer interval would be longer due to the other timer object having to do things and thereby 'suspending' the count for the first timer. I have not tested this, but that feels typically something that would happen in NAV.
  • Captain_DX4Captain_DX4 Member Posts: 230
    How I would attempt to determine the multi-threading:

    I would attempt a test by writing a single-instance codeunit which writes a record with a datetime upon receipt of a message in the queue, then would wait 10 seconds, and finally write again with the current datetime (thereby ending the codeunit). I would make sure a COMMIT exists in after writing the first record, but before the 10 second delay (releasing the table lock). I would copy this code to another single-instance codeunit and modify it to read a separate message queue. Then I would create a routine that will write a message to one queue and then another (as simultaneous as I can get it to occur).

    I would then run my NAS, which should load both single-instance codeunits, and fire my test messages out to both queues. If the first records written to my test table from each codeunit were 10 seconds apart, then we know NAS only handles a single thread. If they are written to the table within milliseconds from each other, we know NAS is able to multi-thread.
    Kristopher Webb
    Microsoft Dynamics NAV Developer
  • kinekine Member Posts: 12,562
    1) Do not forget that Sleep is creating opportunity for other processes to be processed... :-)
    2) As you can see in my example, the timer is not suspended, but all triggers are triggered at first occasion after process ends.
    3) Nav is not multithreaded. There will be never two processes running in one time. Do not forget that it is still just NAV client without GUI. You cannot run two processes in NAV client (opened form or report is not process!).
    4) You will be never able to process two queues in one time. It will process the queues on FIFP (first in, first processed ;-)) bases...
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
Sign In or Register to comment.