Hi all!
When I was at the technical conference in Nice last year, I attended the session about performance (BRK224), and during a demo, something interesting was shown: how to add one BOF service as a runtime task to another BOF service in batch.
You can watch the session recording here, the code is shown about 44 minutes, 50 seconds in.
You can watch the session recording here, the code is shown about 44 minutes, 50 seconds in.
Background: Runtime tasks in Dynamics AX 2009
If you are unfamiliar with runtime tasks and how to use them, read my post about batch multithreading for an explanation. The basic principle stays the same, but in the example below, we will be using the Business Operation Framework (aka BOF, aka SysOperation) instead of RunBaseBatch.
Runtime tasks in Dynamics AX 2012 using BOF
The first thing you’ll need to do, is create 2 BOF services, one that will create the runtime tasks, and one that will represent the runtime task. If you don’t know how to do that, read this post: SysOperation Introduction. You can download the xpo file for the following example below.
KlForSubTaskService: the runtime task
This service will be our runtime task. It’s a regular BOF service, nothing special about it. In my example, the service operation contains some testing code so we can see if our service is working:
class KlForSubTaskService
{
}
[SysEntryPointAttribute]
public void runSubTask(KlForSubTaskDataContract _klForSubTaskDataContract)
{
info(strFmt("%1", _klForSubTaskDataContract.parmTheInt()));
}
{
}
[SysEntryPointAttribute]
public void runSubTask(KlForSubTaskDataContract _klForSubTaskDataContract)
{
info(strFmt("%1", _klForSubTaskDataContract.parmTheInt()));
}
The data contract for this service has one member:
[DataContractAttribute]
class KlForSubTaskDataContract
{
Integer theInt;
}
[DataMemberAttribute]
public Integer parmTheInt(Integer _theInt = theInt)
{
theInt = _theInt;
return theInt;
}
class KlForSubTaskDataContract
{
Integer theInt;
}
[DataMemberAttribute]
public Integer parmTheInt(Integer _theInt = theInt)
{
theInt = _theInt;
return theInt;
}
KlForBatchJobService: Batch header service
This is the service that will create the runtime tasks. Starting for a regular BOF service, make sure that the service class extends SysOperationServiceBase. This enables us to call the isExecutingInBatch() method later on.
class KlForBatchJobService extends SysOperationServiceBase
{
}
{
}
The service operation that creates the runtime tasks looks like this:
[SysEntryPointAttribute]
public void createTasks()
{
BatchHeader batchHeader;
SysOperationServiceController controller;
KlForSubTaskDataContract dataContract;
int i;
;
// for demo purposes, loop 10 times to add 10 runtime tasks
for(i=1;i<=5;i++)
{
if(this.isExecutingInBatch() && !batchHeader)
{
// if no batchheader has been set yet, get it
batchHeader = this.getCurrentBatchHeader();
}
// create new controller for the runtime task
controller = new SysOperationServiceController(classStr(KlForSubTaskService), methodStr(KlForSubTaskService, runSubTask));
// get the data contract
dataContract = controller.getDataContractObject('_klForSubTaskDataContract');
// initialize variables for the data contract
dataContract.parmTheInt(i);
if(this.isExecutingInBatch())
{
// code is running in batch, so add a runtime task
batchHeader.addRuntimeTask(controller, this.getCurrentBatchTask().RecId);
}
else
{
// not in batch
// by default, the tasks will execute in reliable asynchronous mode,
// but you could override it so it executes synchronous
//controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
// not in batch, just run it
controller.run();
}
}
if(batchHeader)
{
// save the batchheader if it has been created
batchHeader.save();
}
}
public void createTasks()
{
BatchHeader batchHeader;
SysOperationServiceController controller;
KlForSubTaskDataContract dataContract;
int i;
;
// for demo purposes, loop 10 times to add 10 runtime tasks
for(i=1;i<=5;i++)
{
if(this.isExecutingInBatch() && !batchHeader)
{
// if no batchheader has been set yet, get it
batchHeader = this.getCurrentBatchHeader();
}
// create new controller for the runtime task
controller = new SysOperationServiceController(classStr(KlForSubTaskService), methodStr(KlForSubTaskService, runSubTask));
// get the data contract
dataContract = controller.getDataContractObject('_klForSubTaskDataContract');
// initialize variables for the data contract
dataContract.parmTheInt(i);
if(this.isExecutingInBatch())
{
// code is running in batch, so add a runtime task
batchHeader.addRuntimeTask(controller, this.getCurrentBatchTask().RecId);
}
else
{
// not in batch
// by default, the tasks will execute in reliable asynchronous mode,
// but you could override it so it executes synchronous
//controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
// not in batch, just run it
controller.run();
}
}
if(batchHeader)
{
// save the batchheader if it has been created
batchHeader.save();
}
}
For this demo, I created a loop that creates 5 runtime tasks.
When you execute this in batch, you can check the batch task history for the batch to see the tasks that have been created.

You can click the Parameters button to verify if the correct values were used to execute the task.
When you execute this in batch, you can check the batch task history for the batch to see the tasks that have been created.
You can click the Parameters button to verify if the correct values were used to execute the task.
You can download the XPO here.
Aucun commentaire:
Enregistrer un commentaire