web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Answered

SysOperationServiceController wrapper - call multiple controllers from within a controller

(0) ShareShare
ReportReport
Posted on by 3,542

Hi folks

I have a series of SysOperation jobs. The jobs need to be able to run separately - hence the reason I created a job for each. Now I want to create a parent job that calls all the separate ones.

Let's say I have 4 jobs: XYZJobAController, XYZJobBController, XYZJobCController and XYZJobDController. Each of them have a contract class and an operation class. Then I have a wrapper controller XYZJobWrapperController (I'm not yet sure whether it should have its own contract and operation classes). Some of the jobs are dependant and some are not.

What is the best/appropriate/recommended method to run controllers A to D from within the wrapper?

There are numerous examples in the standard application. But they are all so different - I am not sure which I should follow. So the question is more about which method to use instead of how to do this.

If this question seems too broad to you, the reader, then it is not for you to answer.

Thanks for your attention.

I have the same question (0)
  • Pete Alberts Profile Picture
    3,542 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    Placing the logic in the service class is further down than the controller's run method.

    I have looked at a lot of examples - most of them utilise run(). But just because everyone does something in a certain way does not mean it is correct.

    I think I have a decent understanding of what is going on (at least more than yesterday). And in my opinion the logic should be written in doBatch().

    doBatch() is called if the process needs to be scheduled for batch. If we put our logic in run() we need to write extensive logic to determine which process is the current one, whether it should be split and so forth.

    With doBatch() we know we are in the header process (if we create the sub processes correctly) and we know we are scheduling for batch processing.

    And then it seems to me that SysOperation was designed for a specific process (which makes sense). The logic in SysOperationController.doBatch() is proof enough for me. So if we are trying to manage multiple process I wonder whether we should use SysOperation at all. In any case, I do not have the time for that. So the interim solution would be to overwrite doBatch() - simply not calling super().

    Here is a version of what I think this should be done:

    final class XYZChristmasBonusController extends SysOperationServiceController
    {
        static void main(Args _args)
        {
            XYZChristmasBonusController controller = new XYZChristamsBonusController();
            controller.initializeFormArgs(_args);
            controller.startOperation();
        }
        
        protected boolean canRunInNewSession()
        {
            return true;
        }
        
        private XYZChristmasBonusContract contract()
        {
            return this.getDataContractObject();
        }
        
        Batch doBatch()
        {
            Batch doBatch;
            
            ttsbegin;
            BatchHeader batchHeader = this.batchInfo().parmBatchHeader(); //here we get the values supplied by the user
            
            for (MonthsOfYear month = MonthsOfYear::January; month <= MonthsOfYear::December; month  )
            {
                XYZChristmasBonusController controller = new XYZChristmasBonusController();
                controller.initializeFromArgs(this.parmArgs());
                controller.parmExecutionMode(SysOperationExecutionMode::Synchronous); //very important - otherwise this process (once executed by batch server), will also call doBatch(). And somewhere in SysOperation there is a comment that a batch process should always be Synchronous
                controller.contract().parmMonthOfYear(month);
                controller.batchInfo().parmCaption(strFmt("Calculation of Pete's christmas bonus, portion %1",month));
                
                //if you do not want the tasks to show up on the bathcjob form, then you can use addRuntimeTask
                batchHeader.addTask(controller);
            }
            
            batchHeader.save();
            ttscommit;
            
            //do not call super - SysOperation is engineered to process a single task, not multiple ones.
            //And then the current task/process is not relevant - it is only used to schedule the sub tasks
            //We can probably write extensive logic to not "throw away" the current process/batchInfo,
            //For example we can add it as one of the portions... But I don't want to.
            //super()
            
            //nothing is done with the return value. So null is okay. In any case - I don't know what anyone will want to do with the return value for this method
            return doBatch;
        }
    }
    
    final class XYZChristmasBonusOperation extends SysOperationServiceBase
    {
        void operation(XYZChristmasBonusContract _contract)
        {
            if (this.isExecutingInbatch()) //alternatively we can test for _contract.parmMonthOfYear() == MonthsOfYear::None
            {
                this.processMonth(_contract.parmMonthOfYear());
            }
            else
            {
                for (MonthsOfYear month = MonthsOfYear::January; month <= MonthsOfYear::December; month  )
                {
                    this.processMonth(month);
                }
            }
        }
        
        private void processMonth(MonthsOfYear _month)
        {
            //massive logic
        }
    }

    I hope this helps anyone that has the same sort of question as myself.

    Thanks Sergey for all the help - much appreciated.

  • Sergei Minozhenko Profile Picture
    23,093 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    Hi Pete

    If you want to use SysOperation framework, you can extend your service class from SysOperationServiceBase class, which will provide you with methods: isExecutingInBatch and getCurrentBatchHeader and put all your code related to additional batch tasks creation to service method.

    BR, Sergey

  • Pete Alberts Profile Picture
    3,542 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    If I want to get the current batch header, I will need to place the code somewhere in my controller. Is run() the appropriate place? It feels too late to me (maybe due to a lack of knowledge). The extra and split tasks should be determined and created before run(). Or not?

  • Sergei Minozhenko Profile Picture
    23,093 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    Hi Pete

    In your case, I suggest creating a new controller, contract and service class to orchestrate batch task creation. And, unfortunately, I believe you should combine 4 contracts into one big contract (it will be some kind of duplication).

    When you create a batch task you would need to copy data from "orchestrate" contract class to particular contract class for the batch task

    something like

    public void createTask(orchestrateContract _orchestrateContract)
    {
    		ttsbegin;
    
            batchHeader = BatchHeader::construct();
            
            batchHeader.parmCaption('My batch job');
    		
    		XYZJobAController controller1 = XYZJobAController::construct(_args);
    
            XYZJobAContract XYZJobAContract = controller1.getDataContractObject();
    
            XYZJobAContract.parmField1(_orchestrateContract.parmField1());
    
            batchHeader.addTask(controller1);
    
    		XYZJobBController controller2 = XYZJobBController::construct(_args);
    
            XYZJobBContract XYZJobBContract = controller2.getDataContractObject();
    
            XYZJobBContract.parmField2(_orchestrateContract.parmField2());
    
            batchHeader.addTask(controller2);
            
            ....
            
            batchHeader.save();
    		
    		ttsCommit;
    }

    If you want to create a sub-task for orchestrator controller batch job, you can find the current batchHeader with getCurrentBatchHeader method on SysOperationServiceBase class.

    BR, Sergey

  • Pete Alberts Profile Picture
    3,542 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    Hi Sergey

    From your response I realise that my other post is more or less the same question. If you'd be so kind to copy and paste your response there or something I will be able to close the thread.

    I have spent the last hour or two on the reference you supplied. It is very much what I was looking for, thanks. If you do not mind a further question:

    In all of the examples the jobs/controllers are scheduled by a separate class. But what about the dialog? How do I tweak that code to still open the dialog for the first controller (we do not want the dialog to prompt for each task, only the first)? I mean the user still needs to be able to specify a ton of details (not mentioning parameters specific to my job). I have not worked with BatchHeader or batch job's directly before. I have always just used a controller and let the standard application take care of the rest.

  • Verified answer
    Sergei Minozhenko Profile Picture
    23,093 on at
    RE: SysOperationServiceController wrapper - call multiple controllers from within a controller

    Hi,

    You can check the article www.linkedin.com/.../, there is an example of how to create a batch task for a controller in class ScheduleDemoIndividualTasksJob. In your case, you would need to create 4 different tasks (for each controller class) and add dependencies between each task if needed. I would say you need own contract class for the parent controller because you need to specify parameters for child jobs somehow. Or you can create a batch job manually and add all tasks and dependencies manually.

    BR, Sergey

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

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Andrés Arias – Community Spotlight

We are honored to recognize Andrés Arias as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
Sohaib Cheema Profile Picture

Sohaib Cheema 882 User Group Leader

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 723 Super User 2025 Season 2

#3
CA Neeraj Kumar Profile Picture

CA Neeraj Kumar 518

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans