web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Microsoft Dynamics AX (Archived)

How to limit a process to one session?

(0) ShareShare
ReportReport
Posted on by

I would like to limit a process that uses a COM interface to another system to just the one session. We have had occurrences were two users have made updates to the same record.

My current thinking is to loop through xSessions and scan the call stack for an occurrence of that particular class.

What would you suggest? Am I missing some simple answer here?

Thanks for your help.

*This post is locked for comments

I have the same question (0)
  • Suggested answer
    Denis Patrakov Profile Picture
    on at

    [quote user="sams9"]We have had occurrences were two users have made updates to the same record.[/quote]Do users update records in AX database or in another system's database? If in AX then you should just rewrite your code to handle such situations, maybe you should disable optimistic concurrency for the table that is updated.

  • Community Member Profile Picture
    on at

    No this process is updating records in a 3rd party app so scoping in AX is not going to be good enough. Looping through xSessions works but I'm not sure it's the best option?!

  • Verified answer
    Denis Patrakov Profile Picture
    on at

    Anyway you can't get the call stack of another session - only the one of the current session. And I believe that limiting the number of AX sessions that connect to a 3rd party app and update records in it's database is not a solution. What if someone runs his own app that connects to this 3rd party app and updates data concurrently with AX sessions? How are you going to prevent this? I think the best way is to use database locks to serialize updates from concurrently running clients. If AX updates data in a 3rd party database directly then it should lock the updated record correctly (e.g. use pessimistic concurrency model) and check if the record is ok after acquiring a lock and before updating the record. If it updates data indirectly via a 3rd party app and that app can't serialize updates then it's obviously poorly designed. In that case and assuming that AX is the only app that issues updates you can implement a serialization in the AX database. You can create a table with a record or records that correspond to the data in the 3rd party DB that AX updates. AX then should acquire a lock for such a record or records in it's own DB before issuing updates and release the lock afterwards.

  • Suggested answer
    Mykola Galak Profile Picture
    on at

    It looks like you'd like to implement singleton pattern for multiple AX sessions. Your class that talks to COM interface should check if other instance already exists. One of the possible ways to do it is to lock some record with pessimisticlock each time you are creating instance of the class and release lock when class finalized all the communication with the COM. In this case if session aborts unexpectedly lock will be released automatically.

    If you need to implement singleton pattern within single AX sessions check this link out: www.axaptapedia.com/Singleton_pattern

  • Community Member Profile Picture
    on at

    Hi gl00mie,

    I'm able to scan all call stacks, here is a working example:

            MyClass     myClass;
            str         callStack;
            xSession    session;
            Counter     i;
            int         classNamePos;
            #AOT
            ;

            myClass = MyClass::construct();

            for (i = 1; i <= xSession::maxSessionId(); i++)
            {
                session = new xSession(i, true);

                if (session && session.userId() && session.sessionId() != sessionId())
                {
                    callStack = con2Str(xSession::xppCallStack());
                    classNamePos = strScan(callStack, #ClassesPath + '\\' + classstr(myClass), 1, strLen(callStack));

                    if (classNamePos > 0)
                    {
                        warning(strFmt("%1 is currently running this function.", (select userInfo where userInfo.Id == session.UserId()).Name));
                        return;
                    }
                }
            }

    The idea of creating a temp table and then locking records there might be a better way.

    Thanks for all your help.

  • Community Member Profile Picture
    on at

    Hi Mykola,

    Thanks for the suggestion of using the singleton pattern but that seems to only work to stop multiple sessions from the same user? Unless I haven't implemented it correctly.

    Again I think record locking might be the go here?!

  • Verified answer
    Mykola Galak Profile Picture
    on at

    Scanning of call stack is not the best option because scan occurs periodically and the class can be instantiated between scans. Best option is kind of event thing. Ideally your COM class should decide itself if it is allowed to call COM interface.

    All AX clients talk to AOS(s) and AOS(s) talks to the database. Therefore database table is the best place to store state of the COMclass. It will work for all AX clients (including BC sessions), for all users.

    1. Create table COMstate with field key

    2. Create record in table COMstate and set key=1

    3. In method that calls COM interface lock the record and invoke COM interface logic:

    ttsbegin;

    select pessimisticlock COMstate

        where COMstate.Key == 1

    //call COM interface logic

    //ttscommit;

    If two users start two AX clients and call COMclass, second one will wait for first one to release the record. If one of the clients terminates abnormally the lock will be released automatically.

  • Denis Patrakov Profile Picture
    on at

    [quote user="sam9"]I'm able to scan all call stacks, here is a working example:

    for (i = 1; i <= xSession::maxSessionId(); i++)
    {
        session = new xSession(i, true);
        if (session && session.userId() && session.sessionId() != sessionId())
        {
            callStack = con2Str(xSession::xppCallStack());

    [/quote]I'm afraid your example is working not quite the way you expect: here you enumerate all sessions but every time you get the call stack of the current session. Note that xppCallStack() is a static method yet it doesn't accept a session id as an argument so it can't figure out that you want to get another session's call stack. Just check out your code under a debugger and you will see that you get the same call stack every time.

  • Community Member Profile Picture
    on at

    This is rather embarrassing, I thought I had the answer there and every silly little test I used confirmed the solution was "working", I hang my head in shame.

    I will implement the DB lock system both of you suggested earlier.

    Thank you both.

  • Community Member Profile Picture
    on at

    Is there a way to display a warning and abort the process if the record in the DB is already locked? So instead of it waiting for the lock to be removed, I would like it to display a message and stop that process. Any ideas on how to achieve that?

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > 🔒一 Microsoft Dynamics AX (Archived)

#1
Martin Dráb Profile Picture

Martin Dráb 4 Most Valuable Professional

#1
Priya_K Profile Picture

Priya_K 4

#3
MyDynamicsNAV Profile Picture

MyDynamicsNAV 2

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans