Skip to main content
Matrix42 Self-Service Help Center

Migrating Engines to Support Engine Activation Sequences

Overview

On this page, you may find how to adjust the implemented Engine in order to support running Engine Activation Sequences.

Running Engine Activation tasks in a sequence was introduced in 10.0.4 release version. 

Engine Activation Sequences allow running tasks within an Engine Activation in a specific order.

When Engine Activation is activated manually or by a specified schedule, the Matrix Engine Scheduler service runs root tasks in the Engine Activation (which do not depend on another task) and stores in cache the data about the dependent tasks to be run in a specified order. 

When running a specific task from Engine Activation, the Matrix Engine Scheduler checks if there are dependent tasks:

  • ❌ no dependent tasks: in case there are no dependent tasks, the task will be activated without a callback.
  • ✔️ with dependent tasks: if there are dependent tasks, the Scheduler will check if the callback interface is supported by the Engine controller for this task.
    • ❌ callback interface is not supported: if the callback interface is not supported, the task itself and all its dependent tasks will not be activated, and an error message will be added into the Scheduler log.
    • ✔️ callback interface is supported: if callback interface is supported, the Scheduler will activate the task with additional callback data which allows the task to report to the Scheduler about its completion.

When the scheduler is reported that a specific Engine Activation task is completed successfully, it looks in cache for data about this specific Engine Activation Sequence and runs dependent tasks if any. If the Engine Activation task is completed with an error, the Matrix Engine Scheduler will not activate dependent tasks.

The Scheduler stores data about dependent tasks tree for specific Engine Activation Sequence in the cache and dependent tasks will not be activated when specific task reports about its completion but data about specific Engine Activation Sequence is not found in the Scheduler cache.

The cache is lost in the following cases:

  • Cache expiration in 24 hours: data about specific Engine Activation Sequence instance is stored in cache for 24 hours after activation has started. After that period data will be invalidated and removed from cache.
  • Running new instance of the same Engine Activation: the Scheduler removes from cache the data about previous instances of the same Engine Activation.
  • Computer reboot: All cache data are lost if the computer is rebooted or the Matrix Engine Scheduler service is restarted.

 

User Interface

Engines that Support Engine Activation Sequences have the PLBEEngineClassBase.IsEndCallbackSupported attribute set to 1 (true):

01Engines_support_sequence_true1.png

Setting the PLBEEngineClassBase.IsEndCallbackSupported attribute to 1 (true) for Engines that do not support callbacks will cause failures when running specific Engine Activation task with dependencies and as result, neither dependent tasks nor the task itself won’t be run.

Engine Dependencies are configured in the Administration application →  Services & Processes → Engine Activations → create new or edit → Activated Engines section:

03activated_engines_new_item.png
 

The Start After includes only those Engines which were added and saved in the edited Engine Activation and are marked as supporting Engine callback interface (IsEndCallbackSupported attribute in PLBEEngineClassBase data definition):

06engine_activation_starts_after.png

For more information about Engine Activation Sequences Configuration in the user interface see Engines page.

Engine development: callback interface

Interfaces and enumerations

To be specified as parent tasks in Engine Activation, Engine should implement a callback interface that allows notifying the Engine Scheduler service when the Engine Activation Task is finished.


Engine controller should implement the IRemoteEngineCallback interface (update4u.SPS.Engines. IRemoteEngineCallback in update4u.SPS.Engines assembly) which extents IRemoteEngine interface with the following method:

void ActivateSubscriptionWithCallback(byte[] subscriptionParams, EngineActivationTaskCallBackData taskCallBackData);
  • subscriptionParams – activation task parameters, the same meaning as subscriptionParams parameter in ActivateSubscription method of IRemoteEngine interface;
  • taskCallBackData – callback data which allow to identify Engine Activation task in Engine Activation instance when reporting tasks state to Engine Scheduler service.

 

Engine Worker should implement IremoteWorkerWithCallback interface (update4u.SPS.Engines. IRemoteWorkerWithCallback in update4u.SPS.Engines assembly) which extents IremoteWorker interface with the following method:

EngineActivationTaskCallBackData ActivateWithResult(DTO activationParms, EngineActivationTaskCallBackData callbackData);
  • activationParms – activation task parameters, the same meaning as activationParms parameter in Activate method of IScheduledService interface (ancestor of IRemoteWorker interface);
  • taskCallBackData – callback data which allow identifying Engine Activation Task in Engine Activation Sequence when reporting tasks state to Engine Scheduler service;
  • return value – changed taskCallBackData parameter.

 

EngineActivationTaskCallBackData – class which is used to report the Engine Scheduler service about Engine Activation Task state.

Properties:

  • Guid ActivationSequenceId  - Engine Activation instance ID, used by Engine Scheduler service to identify Engine Activation instance data in the cache, shouldn’t be changed by Engine controller or Engine Worker;
  • Guid EngineActivationTaskId – ID of specific Engine Activation task, used by Engine Scheduler service to identify Engine Activation task in Engine Activation instance data, shouldn’t be changed by Engine controller or Engine Worker;
  • EngineActivationState ActivationState – Engine Activation task state. EngineActivationState is enumeration with following values:
    • Unknown - status is unknown, do not use this status in Engine Worker;
    • Started - task started synchronously, do not use this status in Engine Worker;
    • StartedAsyncCallBack - task/process started asynchronously and has child processes;
    • Completed - task/process finished successfully;
    • Failed - task/process failed.
  • Dictionary<Guid, EngineActivationState> ProcessObjects – contains a list of child asynchronous processes that have to report their end status separately:
    • Key – process ID (should be absolutely unique but not for specific task activation only);
    • Value – process state (initially should be StartedAsyncCallBack). Engine Activation State:
      • Failed: Engine Activation task is automatically recognized as Failed when it has child processes and at least one child process is reported as failed; dependent task will not be activated.
      • Completed: Engine Activation task is automatically recognized as completed when it has child processes, and all processes are reported as completed; dependent tasks will be activated.

 

Reporting the Engine Activation task status

We recommend using EngineControllerWithCallback and EngineWorkerWithCallBack (update4u.SPS.Engines assembly) as base classes for Engine controller and Engine worker.

EngineControllerWithCallback already reports the task status to the Engine Scheduler service (status report returned by EngineWorkerWithCallBack.ActivateWithResult method).

EngineWorkerWithCallBack implements the base method Activate, as calling ActivateWithResult method with taskCallBackData parameter set to null. 

For synchronous Engine Workers that inherit EngineWorkerWithCallBack, the only thing to be implemented is ActivateWithResult method and return updated task status as in this example:

public override EngineActivationTaskCallBackData ActivateWithResult(DTO activationParms, EngineActivationTaskCallBackData callbackData)

{
  try
  {
    //////////////
    //Do work here
    //////////////
    if (callbackData != null)
    {
      callbackData.ActivationState = EngineActivationState.Completed;
    }
  } 
  catch (Exception e)
  {
    if (callbackData != null)
    {
      callbackData.ActivationState = EngineActivationState.Failed;
    }
  }
  return callbackData;
}


For Engine workers which start additional child processes asynchronously, the callbackData.ProcessObjects should contain a list of unique process IDs and child processes should report their end status to the Engine Scheduler service. Engine worker example:

public override EngineActivationTaskCallBackData ActivateWithResult(
  DTO activationParms,
  EngineActivationTaskCallBackData callbackData)
{
  var processObjects = new List < Guid > ();
  ....
  try
  {
    foreach(var processData in activationData)
    {
      ...
      var processId = RunProcess(processData);
      processObjects.Add(processId);
      ...
    }
    ...
    if (callbackData != null)
    {
      callbackData.ActivationState = processObjects.Count > 0
        ? EngineActivationState.StartedAsyncCallBack
        : EngineActivationState.Completed;
      callbackData.ProcessObjects.Clear();
      foreach(var processObject in processObjects)
      {
        callbackData.ProcessObjects.Add(processObject, EngineActivationState.StartedAsyncCallBack);
      }
    }
  } 
  catch (Exception e)
  {
    if (callbackData != null)
    {
      callbackData.ActivationState = EngineActivationState.Failed;
    }
  }
  return callbackData;
}

Reporting child process end status to the Engine Scheduler service example:

using update4u.SPS.Engines;
using update4u.SPS.Engines.Scheduler;
...
...
public class SomeAsyncProcessOrSomeAsyncProcessEndHandler
{
  ...
  public void Handle(SomeProceeResult processResult)
  {
    ...
    NotifyActivationProcessObjectState(processResult.ProcessId,
      processResult.Result == ProcessStatus.Ok
        ? EngineActivationState.Completed
        : EngineActivationState.Failed);
  }
  public void Process(ProcessData processData)
  {
    EngineActivationState processState;
    try
    {
    ...
      processState = EngineActivationState.Completed;
    }
    catch (Exception e)
    {
      processState = EngineActivationState.Failed;
    }
    NotifyActivationProcessObjectState(processData.ProcessId, processState);
  }
 
  private void NotifyActivationProcessObjectState(Guid processId, EngineActivationState state)
  {
    try
    {
      var schedulerWorker = EngineProxy.GetWorker(typeof (ISchedulerWorker)) as ISchedulerWorker;
      if (schedulerWorker == null)
      {
          _log.Error("Failed to report process object status: couldn't resolve Scheduler.");
          return;
      }
      schedulerWorker.ReportActivationObjectState(processId, state);
    }
    catch (Exception e)
    {
      _log.Error($"Failed to report engine activation process object status: {e}");
    }
  }
}

To report Engine Activation Task status manually (instead of using EngineControllerWithCallback and EngineWorkerWithCallBack base classes and recommended templates), use the following example:

using update4u.SPS.Engines;
using update4u.SPS.Engines.Scheduler;
...
...
public class SomeEngineControllerOrEngineWorkerClass
{
  ...
  protected void NotifyEngineActivationTaskEnd(EngineActivationTaskCallBackData callBackData)
  {
    if (callBackData == null)
    {
        return;
    }
    
    try
    {
      var schedulerWorker = EngineProxy.GetWorker(typeof (ISchedulerWorker)) as ISchedulerWorker;
      if (schedulerWorker == null)
      {
          Log.Error("Failed to report engine activation task status: couldn't resolve Scheduler.");
          return;
      }
      schedulerWorker.EngineActivationStateCallback(callBackData);
    } 
    catch (Exception e)
    {
        _log.Error($"Failed to report engine activation task status: {e}");
    }
  }
}
  • Was this article helpful?