Batch Bundling Multi threading in x++ in D365F&O.

Hi Viewers,

๐Ÿงบ Batch Bundling: The Efficiency Trap

Batch Bundling is a simple idea: Take a big pile of work and divide it into smaller, equal-sized groups—called bundles—and assign each group to a different processor.

Think of it like dividing a huge stack of mail into 10 smaller bundles, and giving one to each of your 10 assistants.

Cons:

However, a major drawback can occur: even if every bundle contains the same quantity of work items, the effort required for each item may be vastly different.

The problem comes down to complexity. While each bundle has the same number of items (say, 100 sales orders), the work required for each item isn't the same. One bundle might contain 100 simple, single-item orders. Another might contain 100 massive, multi-line corporate orders.

The assistants who got the simple bundles are done in minutes. But the others are still slogging through the complex work. Now, you have a bunch of people sitting idle, waiting for the others to finish. You've lost the efficiency you tried to gain.


Process:

To Divide make bundle and assign the task to batch. 

  • We need a controller class, contract class and service class.  Generally prefix with processing
To process actual business logic.
  • We need normal controller class, contract class and service class.


Processing Contract class.

internal final class ProcessingContract{

    private int numberOfThreads;


    [DataMemberAttribute]
    public int parmNumberOfThreads(int _numberOfThreads = numberOfThreads)
    {
        numberOfThreads = _numberOfThreads;

        return numberOfThreads;
    }
}

Process Controller class:

internal final class ProcessingController extends SysOperationServiceController implements BatchRetryable
{

    public static void main(Args _args)
    {
       ProcessingController controller;

        controller = ProcessingController::construct();
        controller.parmArgs(_args);
        controller.parmLoadFromSysLastValue(false);

        ProcessingContract contract = controller.getDataContractObject() as ProcessingContract;
        contract.parmNumberOfThreads(8);

        controller.startOperation();
        if (FormDataUtil::isFormDataSource(_args.record()) == true)
        {
            FormDataUtil::getFormDataSource(_args.record()).research(true);
        }
    }
 
    public static ProcessingController construct(SysOperationExecutionMode _executionMode = SysOperationExecutionMode::Synchronous)
    {
        ProcessingController controller;

        controller = new ProcessingController();
        controller.parmExecutionMode(_executionMode);

        return controller;
    }
 public boolean isRetryable()
    {

        return true;
    }
}


Process Service class:

This is class actually creating the bundles as a task (calls business logic service class) and assign to the batch.

internal final class ProcessingService extends SysOperationServiceBase
{
    private container workOrderList;
 public void process(ProcessingContract _contract)
    {
        //prepare work orders to be processed
        this.prepareWorkOrderList();

        if (this.isExecutingInBatch())
        {
            int workOrderCount = conLen(workOrderList);
            if (workOrderCount > 0)
            {
                int maxThreadCount = min(workOrderCount, _contract.parmNumberOfThreads());
                if(maxThreadCount == 0)
                {
                    maxThreadCount = 1;
                }

                int baseSize   = workOrderCount div maxThreadCount;
                int extra      = workOrderCount mod maxThreadCount;

                container woTaskList = conNull();

                int  currentThreanNum = 1, countInCurrentList = 0;

                BatchHeader currentBatchHeader = this.getCurrentBatchHeader();

                //Creating tasks
                for (int i = 1; i <= workOrderCount; i++)
                {
                    woTaskList += conPeek(workOrderList, i);
                    countInCurrentList++;

                    int limit = baseSize + (currentThreanNum <= extra ? 1 : 0);

                    if (countInCurrentList >= limit)
                    {
                        SysOperationServiceController controller = new SysOperationServiceController(classStr(ProcessingTaskService),
                            methodStr(ProcessingTaskService,process), SysOperationExecutionMode::Synchronous);

                        ProcessingTaskContract contract  = controller.getDataContractObject() as ProcessingTaskContract;
                        contract.parmWorkOrderIdList(woTaskList);
                        currentBatchHeader.addTask(controller);

                        woTaskList = conNull();

                        currentThreanNum++;
                        countInCurrentList = 0;
                    }
                }
                currentBatchHeader.save();
            }
        }
        else
        {
            SysOperationServiceController controller = new SysOperationServiceController(classStr(ProcessingTaskService),
                            methodStr(ProcessingTaskService,process), SysOperationExecutionMode::Synchronous);

            ProcessingTaskContract contract  = controller.getDataContractObject() as ProcessingTaskContract;

            contract.parmWorkOrderIdList(workOrderList);
            controller.run();
        }          
    
    }
}


Actual business logic service class.



class ProcessingTaskService extends SysOperationServiceBase
{
    
public void process(ProcessingTaskContract _contract)
    {
        container workOrderList = _contract.parmWorkOrderIdList();

        for (int i = 1; i <= conLen(workOrderList); i++)
        {
            // code
        }
    }

}

Thanks for reading! Like this post if you found it helpful. ๐Ÿ˜€๐Ÿ˜€
And let me know your thoughts in the comments below.๐Ÿ˜‡๐Ÿ˜‡


Comments

Popular posts from this blog

In ax D365F&O post packing slip from shipment through code x++.

Multi select lookup in UI Builder class in D365F&O through x++ code.

Cancel Post packing slip from all Shipments in D365 F&O through X++