Threading in Dynamics AX

Threading in AX 2009 is different from threading in C#.  In C# you can spawn up threads and have them do whatever they do.  The same thing is available in AX using the Thread class but it isn’t the optimal or recommended way to spawn threads in AX.  This is because AX has AOS instances and batches.  When you create new instances of the Thread class you do this on a single AOS rather than taking advantage of multiple AOS instances.  You could throw those instances of the Thread classes into a batch but then the batch framework will not be helpful to you in terms of catching exceptions and debugging your classes. 

Instead of using the Thread class use the BatchHeader X++ class.  Call the addRuntimeTask method on the BatchHeader class to add your logic.  The only requirement for your class that you add as a runtime task is that it must extend RunBaseBatch.  The runtime tasks are easy to use and they are designed to work with the batch framework.  Ultimately you get a better debugging experience, you can distribute the tasks across multiple AOS instances and you can catch exceptions easily.  By utilizing this framework you don’t have to think about managing the threads.

The information below is from the Inside Microsoft Dynamics AX 2009 book.  It describes the BatchHeader class and the methods on it and then provides an example of how it works.  The SalesFormLetter class in AX uses the BatchHeader class as well.

The BatchHeader class is part of the API set in the batch server framework that enables developers to programmatically create or modify batch jobs, tasks and their dependencies as needed as well as to dynamically create run-time batch tasks on the fly.  The batch server framework APIs are particularly useful for advanced scenarios requiring complex logic or processing of large batch jobs, such as inventory closing or data upgrades.

addDependency – Defines the dependencies between the tasks added to the BatchHeader.  The first parameter, batchTaskToRun, defines which task is dependent upon the second parameter, dependsOnBatchTask.  The third optional parameter, batchStatus, allows you to specify the type of the dependency.  By default a dependency of type BatchDependecyStatus::Finished is created, which means that the task starts execution only if the task which it depends on finishes successfully.  Other allowed options are BatchDependencyStatus::Error and BatchDependecyStatus::FinishedOrError.

addTask – Adds an instance of a BatchTask to the BatchHeader.  The BatchTask represents a batch-enabled class that will be scheduled for execution as a task by the BatchHeader.

addRuntimeTask – Adds an instance of a dynamic BatchTask to the BatchHeader.  The BatchTask added exists for only the current run.  It gets copied into the history tables and deleted at the end of the run.  The second parameter, inheritFromTaskId, copies settings such as the batch group and child dependencies from the task specified.

save – Creates a batch job by inserting records into the BatchJob, Batch and BatchConstraints tables where the batch server can automatically pick them up for execution.

construct – Returns an instance of the BatchHeader class which acts as a batch job.  An optional parameter can be passed to the construct method for an existing batch job.

class Batch4DemoClass extends RunBaseBatch

{

    public void run()

    {

        ;

        // The code executed in a batch task

        info(strFmt(“Hello from Batch4DemoClass .run at %1”

            ,DateTimeUtil ::toStr(DateTimeUtil ::utcNow())));

    }

    public container pack()

    {

        return conNull();

    }

    public boolean unpack(container packedClass)

    {

        return true;

    }

}

static void ExampleSchedulingBatchJob(Args _args)

{

    BatchHeader batchHeaders

    RunBaseBatch batchTask1, batchTask2;

    ;

    //create batch header

    batchHeader = BatchHeader::construct();

    batchHeader.parmCaption(“Example of a batch job”);

    //create instances of the classes to use as batch tasks

    batchTask1 = new Batch4DemoClass()

    batchTask2 = new Batch4DemoClass();

    //add the batch tasks to the batch header

    batchHeader.addTask(batchTask1);

    batchHeader.addTask(batchTask2);

    //define a dependency between the batch tasks

    batchHeader.addDependency(batchTask2, batchTask1, BatchDependencyStatus::FinishedOrError);

    //save the batch

    batchHeader.save();

}

Once the ExampleSchedulingBatchJob has been successfully executed in AX go to Administration > Common Forms > Batch job list – User to view the batch job that has been added to the list of batch jobs.  In the form select the added batch job from the list and click the View tasks buttons to view the tasks added to the batch and the dependency between them. 

Note – If the tasks had been added to the batch header by the addRuntimeTask method they would be listed in the form opened by the Views tasks button until the batch is executed.  Once the batch is executed, they are removed.