Multithread based on user count in sys operation framework in D365FO.
- The system will create multiple tasks in the same batch job id.
- Based on user input system will create multiple threads.
Multithread Contract Class :
[DataContractAttribute]
class TestMultiThreadContract
{
private int tasksNumber;
[DataMemberAttribute('Count')]
public int parmParallelTasksNumber(int _tasksNumber = tasksNumber)
{
tasksNumber = _tasksNumber;
return tasksNumber;
}
}
Multithread Controller class:
class TestMultiThreadController extends SysOperationServiceController { protected void new() { super(); this.parmClassName(classStr(openSalesOrderService)); this.parmMethodName(methodStr(openSalesOrderService, createScheduleTask)); this.parmExecutionMode(SysOperationExecutionMode::ScheduledBatch); this.parmDialogCaption("Sales order process"); } public static TestMultiThreadController construct() { return new TestMultiThreadController(); } public static void main(Args args) { TestMultiThreadController::construct().startOperation(); } public ClassDescription defaultCaption() { return "Sales order process"; } }
Multithread Service Class :
class TestMultiThreadService extends SysOperationServiceBase { int numberOfOpenRecord; int numberOfBatchThread; FromDate fromDateFilter; ToDate toDateFilter; Integer numberOfBundleSize; public void createScheduleTask(TestMultiThreadContract _contract) { Integer eachRecordCount; SalesId fromSalesId, toSalesId, lastSalesId; FromDate fromDateId; ToDate toDateId; if (!this.isExecutingInBatch()) { throw error(Error::wrongUseOfFunction(funcName())); } numberOfBatchThread = _contract.parmParallelTasksNumber(); numberOfOpenRecord = this.openSalesOrderCount(); if (numberOfOpenRecord > 0 && numberOfBatchThread > 0) { BatchHeader batchHeader = this.getCurrentBatchHeader(); // how many bundle will run thay will given by user. numberOfBundleSize = numberOfOpenRecord div numberOfBatchThread; SalesTable salesTable; while select SalesId from salesTable order by salesTable.SalesId where salesTable.SalesStatus == SalesStatus::Backorder { eachRecordCount++; if (eachRecordCount == 1) { fromSalesId = salesTable.SalesId; } if (eachRecordCount == numberOfBundleSize) { toSalesId = salesTable.SalesId; TestContract contract; var controller = SysOperationServiceController((classStr(TestMyService), methodStr(TestMyService, processOperation), SysOperationExecutionMode::Synchronous)); contract = controller.getDataContractObject(); contract.parmFromSalesOrderNum(fromSalesId); contract.parmToSalesOrderNum(toSalesId); batchHeader.addRuntimeTask(controller, this.getCurrentBatchTask().RecId); eachRecordCount = 0; } lastSalesId = salesTable.SalesId; } if (eachRecordCount > 0) { toSalesId = lastSalesId; TestContract contract; var controller = SysOperationServiceController((classStr(TestMyService), methodStr(TestMyService, processOperation), SysOperationExecutionMode::Synchronous)); contract = controller.getDataContractObject(); contract.parmFromSalesOrderNum(fromSalesId); contract.parmToSalesOrderNum(toSalesId); batchHeader.addRuntimeTask(controller, this.getCurrentBatchTask().RecId); } batchHeader.save(); } } private int openSalesOrderCount() { SalesTable salesTable; select count(RecId) from salesTable where salesTable.SalesStatus == SalesStatus::Backorder; numberOfOpenRecord = int642int(salesTable.RecId); return numberOfOpenRecord; } }
My Service Class :
class TestMyService extends SysOperationServiceBase { public void AutoPostProcessExecute(TestContract _contract) { #OCCRetryCount if (!this.isExecutingInBatch()) { throw error(Error::wrongUseOfFunction(funcName())); } SalesId fromSalesId = _contract.parmFromSalesOrderNum(); SalesId toSalesId = _contract.parmToSalesOrderNum(); SalesTable salesTable; int counter; while select salesTable order by salesTable.SalesId where salesTable.SalesId >= fromSalesId && salesTable.SalesId <= toSalesId && salesTable.SalesStatus == SalesStatus::Backorder { try { ttsbegin; this.insertSalesOrderIntoCustomTable(salesTable); counter++; ttscommit; } catch (Exception::Deadlock) { retry; } catch (Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } } catch(Exception::DuplicateKeyException) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::DuplicateKeyExceptionNotRecovered; } else { retry; } } else { throw Exception::DuplicateKeyException; } } catch (Exception::Error) { infolog.add(Exception::Error, strFmt("", SalesTable.SalesId)); continue; } catch (Exception::CLRError) { System.Exception ex = CLRInterop::getLastException(); Infolog.add(Exception::CLRError, ex.ToString() ); continue; } } } info(strFmt("%1 Sales order invoiced", counter)); } private void insertSalesOrderIntoCustomTable(SalesTable _salesTable) { MycustomTable mycustomTable; mycustomTable.salesId = _salesTable.salesId; mycustomTable.CustomField1 = _salesTable.CustomField1; mycustomTable.CustomField2 = _salesTable.CustomField2; mycustomTable.insert(); } }
My ContractClass :
[DataContractAttribute] class TestContract { private SalesId fromSalesId; private SalesId toSalesId; [DataMemberAttribute] public SalesId parmFromSalesOrderNum(SalesId _fromSalesId = fromSalesId) { fromSalesId = _fromSalesId; return fromSalesId; } [DataMemberAttribute] public SalesId parmToSalesOrderNum(SalesId _toSalesId = toSalesId) { toSalesId = _toSalesId; return toSalesId; } }
Using RunBase Batch Click here
Keep Daxing!!
No comments:
Post a Comment