| Quintiq file version 2.0 | 
| #parent: #root | 
| Method DoHandleResult (Algorithm algorithm, LibOpt_Task task) as stream[JSON] | 
| { | 
|   Description: | 
|   [* | 
|     The boiler plate of calling the handle result method of the algorithm. | 
|      | 
|     - Log the timings (init, solve and handle result) in the algorithm snapshots. | 
|     - Execute the handle result method. | 
|     - Re-execute if this is configured. | 
|     - Execute rollback logic in `PostHandleResult`. | 
|   *] | 
|   TextBody: | 
|   [* | 
|     transaction := LibOpt_CurrentTransaction::GetCurrentTransaction( this ); | 
|     // Register the task so that the 'RollbackCurrentTransaction' method knows which task belongs to which transaction.  | 
|     // Also, registering the task ensures that any LibOpt_Snapshots that are created this transaction are linked to the task.  | 
|     // The snapshots are also indirectly linked to the SnapshotComponent of the task. This link is required to properly handle rollbacks. | 
|     // Therefore, RegisterTask should be called before any new snapshots are created.  | 
|     istaskregistered := transaction.RegisterTask( task ); | 
|      | 
|     // We break the rule here that snapshots should not be updated later. | 
|     // We do this so we can get the handle result duration even if the handle result throws an error. | 
|     // Note that we update it only in the same transaction. | 
|     snapshot := null( LibOpt_SnapshotAlgorithm ); | 
|     if( task.Run().HasSnapshots() ) | 
|     { | 
|       snapshot := this.CreateAlgorithmSnapshot( algorithm ); | 
|     } | 
|      | 
|     kpi_snapshot_pre := null( LibOpt_SnapshotKPI ); | 
|     kpi := this.PreHandleResult( task, kpi_snapshot_pre ); | 
|      | 
|     scope := task.Scope(); | 
|      | 
|     if( transaction.IsSafe() ) | 
|     { | 
|       // The task is already registered at the beginning of this method, so the BeforeMethodCall_ExistingSafeTransaction method always returns false.  | 
|       transaction.BeforeMethodCall_ExistingSafeTransaction( task ); | 
|       // A user error might occur in DoHandleResultForAlgorithmCall or in other methods called by DoHandleResultForAlgorithmCall.  | 
|       // However, transaction.IsSafe() is true, so we are inside a try{...} block. We have also called BeforeMethodCall_ExistingSafeTransaction. The error is therefore handled gracefully.  | 
|       scope := this.DoHandleResultForAlgorithmCall( algorithm, task ); | 
|       transaction.AfterMethodCall_ExistingSafeTransaction( task, false ); | 
|     } | 
|     else | 
|     { | 
|       try | 
|       { | 
|         // The task is already registered at the beginning of this method, so the BeforeMethodCall_TryBlock method always returns false.  | 
|         transaction.BeforeMethodCall_TryBlock( task ); | 
|         // A user error might occur in DoHandleResultForAlgorithmCall or in other methods called by DoHandleResultForAlgorithmCall.  | 
|         // However, we are inside a try{...} block. We have also called BeforeMethodCall_TryBlock. The error is therefore handled gracefully.  | 
|         scope := this.DoHandleResultForAlgorithmCall( algorithm, task ); | 
|         transaction.AfterMethodCall_TryBlock( task, task.Run(), false ); | 
|       } | 
|       onerror | 
|       { | 
|         LibOpt_SnapshotAlgorithm::CaptureHandleResultDuration( snapshot, algorithm ); | 
|         transaction.OnError( e ); | 
|       } | 
|       onfailure | 
|       { | 
|         LibOpt_SnapshotAlgorithm::CaptureHandleResultDuration( snapshot, algorithm ); | 
|         transaction.OnFailure( e ); | 
|       } | 
|     } | 
|      | 
|     LibOpt_SnapshotAlgorithm::CaptureHandleResultDuration( snapshot, algorithm ); | 
|      | 
|     result := null( stream[JSON] ); | 
|     if( this.ShouldReExecute( algorithm ) ) | 
|     { | 
|       if( not isnull( kpi_snapshot_pre ) ) | 
|       { | 
|         kpi_snapshot_pre.Delete(); | 
|       } | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::FrameworkInitialize() ); | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::FrameworkSolve() ); | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::FrameworkHandleResult() ); | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::Initialize() ); | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::Solve() ); | 
|       LibOpt_AlgorithmStopwatch::Reset( algorithm, LibOpt_SnapshotAlgorithm::HandleResult() ); | 
|       result := this.DoExecute( algorithm, task ); | 
|     } | 
|     else | 
|     { | 
|       this.FinalizeSnapshot( task, scope ); | 
|       if( transaction.IsSafe() ) | 
|       { | 
|         // The task is already registered at the beginning of this method, so the BeforeMethodCall_ExistingSafeTransaction method always returns false.  | 
|         transaction.BeforeMethodCall_ExistingSafeTransaction( task ); | 
|         // A rollback may occur in the `PostHandleResult` | 
|         this.PostHandleResult( task, kpi ); | 
|         transaction.AfterMethodCall_ExistingSafeTransaction( task, false ); | 
|       } | 
|       else | 
|       { | 
|         try | 
|         { | 
|           // The task is already registered at the beginning of this method, so the BeforeMethodCall_TryBlock method always returns false.  | 
|           transaction.BeforeMethodCall_TryBlock( task ); | 
|           // A rollback may occur in the `PostHandleResult` | 
|           this.PostHandleResult( task, kpi ); | 
|           transaction.AfterMethodCall_TryBlock( task, task.Run(), false ); | 
|         } | 
|         onerror | 
|         { | 
|           LibOpt_SnapshotAlgorithm::CaptureHandleResultDuration( snapshot, algorithm ); | 
|           transaction.OnError( e ); | 
|         } | 
|         onfailure | 
|         { | 
|           LibOpt_SnapshotAlgorithm::CaptureHandleResultDuration( snapshot, algorithm ); | 
|           transaction.OnFailure( e ); | 
|         } | 
|       } | 
|       result := this.ContinueWithoutFinalize( task, this.Next(), scope ); | 
|     } | 
|      | 
|     // UnregisterTask can only be called after PostHandleResult is called, because PostHandleResult might roll back the current transaction. | 
|     // This rollback requires that the task is still registered.  | 
|     transaction.UnregisterTask( task, istaskregistered ); | 
|      | 
|     return result; | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |