How do I handle AX timeouts where the operation continues on? Abort not working?

254 views Asked by At

I have a custom AX service operation that can take 5+ minutes to complete and I'm trying to figure out how to abort it from my .NET application, but aborting the client doesn't seem to do anything?

The problem is if I call the operation and the service times out, the AX operation continues on until completion, so I lose visibility to the results (success/failure). An example being a long-running posting operation where I don't know if it posted successfully or not.

I've created a simple demo app where I can't seem to get the operation to abort. In the below code I just create a transaction (ttsbegin/ttscommit), insert into a table at start, sleep, insert into table at end.

Sample AX X++ Service Code:

[SysEntryPointAttribute(true)]
public str callAXTimeDelay(int _sleepSeconds)
{
    Table1                  table1;

    ttsBegin;
    table1.clear();
    table1.SleepData = strFmt("STARTED: %1", DateTimeUtil::utcNow());
    table1.insert();
    ttsCommit;
    
    sleep(_sleepSeconds * 1000);
    
    ttsBegin;
    table1.clear();
    table1.SleepData = strFmt("COMPLETED: %1", DateTimeUtil::utcNow());
    table1.insert();
    ttsCommit;
    
    return strFmt("COMPLETED: %1", DateTimeUtil::utcNow());
}

Then when I call it from .NET, the abort doesn't seem to work? Start/Complete records are still inserted into table1 even though the abort is called before the 15 seconds have completed?

Sample .NET code:

internal class Program
{
    static void Main(string[] args)
    {
        new Program().Run();

        Console.WriteLine("Ended, press any key to exit...");
        Console.ReadKey();
    }

    public void Run()
    {
        AXServicesClient axClient15Sec = new AXServicesClient();
        AXServicesClient axClient5sec = new AXServicesClient();

        var job15sec = DoLongRunningCall(axClient15Sec, 15);
        var job5sec = DoLongRunningCall(axClient5sec, 5);

        try
        {
            var result = Task.Run(() => Task.WhenAny(job15sec, job5sec)).GetAwaiter().GetResult();

            if (result == job15sec)
            {
                Console.WriteLine("job15sec finished first, aborting job5sec");
                axClient5sec.Abort();
            }
            else if (result == job5sec)
            {
                // This code gets executed because the 5 second job completed and
                // it tries to cancel the 15-sec job, but the table ends up with data!
                Console.WriteLine("job5sec finished first, aborting job15sec");
                axClient15Sec.Abort();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e.Message);

            axClient15Sec.Abort();
            axClient5sec.Abort();
        }
        axClient15Sec.Close();
        axClient5sec.Close();
    }

    public async Task<string> DoLongRunningCall(AXServicesClient client, int seconds)
    {
        var result = await client.callAXTimeDelay(new CallContext
        {
            Company = "ABCD",
            Language = "en-us"
        }, seconds);

        return result.response;
    }
}
0

There are 0 answers