Skip to main content

Notifications

Announcements

No record found.

Microsoft Dynamics AX (Archived)

RunBaseBatch used to parallel process long running report items.

Posted on by 85

DAX Tribe,

I need to do the following:

Process a large collection of FixedAsset.AgreementAmendmentTransfers and report on the results.

As these assets are independent, but must all get transferred against the same agreement amendment (which takes a long time -- perhaps a minute apiece) I'd like to batch them up.

So, in groups of X, I'll load a RunBaseBatch task and let the task process these agreement transfers asynchronously.

I see that I can achieve this without too much difficulty.

However, here's the rub, I'd like to get a call-back when all tasks are completed -- so that I can either present a report or send the report in email.

Now, I know that one should be able to just "Batch Tab" process this report - but unfortunately it's not a normal report. It's a Form based report that provides a complex "SELECT all the agreements you'd like to transfer."

So, CAN I either get a callback or interrogate the status of the BatchHeader spin-waiting while the tasks all complete? 

Or is there a better way to do this parallel task processing while remaining in the interactive UI? (In dotnet I'd just queue these up and alert the user when done.) But in X++?

Any assistance would be appreciated.

Thanks,

Dave

*This post is locked for comments

  • Suggested answer
    DaveCline Profile Picture
    DaveCline 85 on at
    RE: RunBaseBatch used to parallel process long running report items.

    Here is one solution to "SpinWait" during a long interactive batch processing session. We interrogate the Batch table, waiting until all RunBaseBatch tasks have completed or errored out.

    public static void BeginAsyncProcessing(MyTable _records)
    {
        #AviFiles
        SysOperationProgress progress = new SysOperationProgress();
        int64 taskCount, taskWaitingCount;
        BatchHeader batchHeader;
        BatchInfo batchInfo;
        Batch batchTasks;
        MyTable currentRecord;
        MyTableBatchTask task;
    
        // Create a batch job here and load the tasks
        info('Long task: Begin');
        batchHeader = BatchHeader::construct();
        batchHeader.parmCaption(strFmt('Batch job for MyTableTasks'));
    
        // Begin the loop to create individual batch tasks - each dedicated to a single worker
        while select _records
        {
            currentRecord.data(_records);
    
            // Each task is created to process a single work item
            // The constructor take parameters which will be used to actually execute the task within the "run()" method
            task = MyTableBatchTask::construct(currentRecord);
            batchInfo = task.batchInfo();
            BatchInfo.parmCaption(strfmt('MyTableBatchTask: Task scheduled assetId: %1', _records.AssetId));
            batchHeader.addTask(task);
            taskCount++;
        }
        batchHeader.save();
    
        // Begin the Spin-Wait process
        // -- we'll interrogate the BATCH table to determine which tasks have completed.
        startLengthyOperation();
        progress.setCaption(strFmt("Agreement amendment transfer progress #%1 count", taskCount));
        progress.setAnimation(#AviUpdate);
        progress.setTotal(taskCount);
    
        while (true)
        {
            taskWaitingCount = -1;
    
            // Fetch the batch records that have NOT finished or are NOT errored out.
            select count(RecId) from batchTasks
               where batchTasks.BatchJobId == batchHeader.parmBatchHeaderId()
                && (batchTasks.Status != BatchStatus::Error && batchTasks.Status != BatchStatus::Finished);
    
            taskWaitingCount = batchTasks.RecId;
    
            // If we still have tasks processing then update the progress bar and continue
            if (taskWaitingCount)
            {
                progress.setText(strfmt("Processing #%1", taskCount - taskWaitingCount));
                progress.setCount(taskCount - taskWaitingCount, 1);
                progress.update();
                System.Threading.Thread::get_CurrentThread().Join(0);
                System.Threading.Thread::Sleep(1000);
            }
            else
            {
                progress.setCount(taskCount, 1);
                break;
            }
        }
        progress.reset();
        endLengthyOperation();
    
        select count(RecId) from batchTasks
            where batchTasks.BatchJobId == batchHeader.parmBatchHeaderId()
            && (batchTasks.Status == BatchStatus::Error);
    
        if (batchTasks.RecId == 0)
        {
            info('MyTableBatch: SUCCESS');
        }
        else
        {
            info('MyTableBatch: ERRORS');
            info(strFmt("%1 of %2 of the processes failed.", batchTasks.RecId, taskCount));
        }
    }


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

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Tips for Writing Effective Suggested Answers

Best practices for providing successful forum answers ✍️

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,280 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,235 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans