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