Managing Command State

A component has access to commandResponseManager which is used to manage the state of commands during its execution. On receiving a command as a part of onSubmit, the component framework adds the command to an internal CommandResponseManager. The component should then update the status of the command using the following API provided in commandResponseManager:

addOrUpdateCommand

Add a new command or update the status of an existing command.

Scala
// after validation of the controlCommand, update its status of successful validation as Accepted
// TODO -- This isn't needed, but it must be part of docs
// commandResponseManager.addOrUpdateCommand(controlCommand.runId, Started(controlCommand.runId))
Java
// after validation of the controlCommand, update its status of successful validation as Accepted
CommandResponse.Accepted accepted = new CommandResponse.Accepted(controlCommand.runId());
// TODO - REALLY?
//commandResponseManager.addOrUpdateCommand(controlCommand.runId(), accepted);

addSubCommand

A received command can be often split into two or more sub-commands. The status of original command can then be derived from the status of the sub-commands. In order to achieve this, a component has to first add the sub-commands against in relation to the parent command using this method.

Scala
shortSetup = Setup(prefix, shortRunning, controlCommand.maybeObsId)
commandResponseManager.addSubCommand(runId, shortSetup.runId)
Java
Prefix prefix = new Prefix("wfos.red.detector");
Setup subCommand = new Setup(prefix, new CommandName("sub-command-1"), sc.jMaybeObsId());
commandResponseManager.addSubCommand(sc.runId(), subCommand.runId());

Setup subCommand2 = new Setup(prefix, new CommandName("sub-command-2"), sc.jMaybeObsId());
commandResponseManager.addSubCommand(sc.runId(), subCommand2.runId());

updateSubCommand

Update the CommandResponse of the sub-command which would trigger the automatic derivation of the status of the original/parent command when status of all the sub-commands have been updated. A CommandResponse indicating failure such as Invalid or Error in any one of the sub-commands would result in the error status of the parent command. Status of any other sub-commands wil not be considered in this case.

Scala
// An original command is split into sub-commands and sent to a component. The result of the command is
// obtained by subscribing to the component with the sub command id.
case _: Completed ⇒
  controlCommand.runId match {
    case id if id == shortSetup.runId ⇒
      currentStatePublisher
        .publish(CurrentState(shortSetup.source, StateName("testStateName"), Set(choiceKey.set(shortCmdCompleted))))
      // As the commands get completed, the results are updated in the commandResponseManager
      commandResponseManager.updateSubCommand(id, Completed(id))
    case id if id == mediumSetup.runId ⇒
      currentStatePublisher
        .publish(CurrentState(mediumSetup.source, StateName("testStateName"), Set(choiceKey.set(mediumCmdCompleted))))
      commandResponseManager.updateSubCommand(id, Completed(id))
    case id if id == longSetup.runId ⇒
      currentStatePublisher
        .publish(CurrentState(longSetup.source, StateName("testStateName"), Set(choiceKey.set(longCmdCompleted))))
      commandResponseManager.updateSubCommand(id, Completed(id))
  }
Java
// An original command is split into sub-commands and sent to a component. The result of the command is
// obtained by subscribing to the component with the sub command id.
ICommandService componentCommandService = runningHcds.get(componentInfo.getConnections().get(0)).get();
componentCommandService.submit(subCommand2, Timeout.durationToTimeout(FiniteDuration.apply(5, TimeUnit.SECONDS)))
        .thenAccept(commandResponse -> {
            if (commandResponse instanceof CommandResponse.Completed) {
                // As the commands get completed, the results are updated in the commandResponseManager
                commandResponseManager.updateSubCommand(subCommand2.runId(), commandResponse);
            } else {
                // do something
            }
        });
Note

It may be the case that the component wants to avoid automatic inference of a command based on the result of the sub-commands. It should refrain from updating the status of the sub-commands in this case and update the status of the parent command directly as required.

query

Query for the result of a command that is already present in the component’s CommandResponseManager.

Scala
// query CommandResponseManager to get the current status of Command, for example: Accepted/Completed/Invalid etc.
commandResponseManager
  .query(controlCommand.runId)
  .map(
    _ ⇒ () // may choose to publish current state to subscribers or do other operations
  )
// Return response
Started(controlCommand.runId)
Java
// query CommandResponseManager to get the current status of Command, for example: Accepted/Completed/Invalid etc.
commandResponseManager
        .jQuery(subCommand.runId(), Timeout.durationToTimeout(FiniteDuration.apply(5, "seconds")))
        .thenAccept(commandResponse -> {
            // may choose to publish current state to subscribers or do other operations
        });

subscribe

Subscribe for the result of a command that is already present in the component’s CommandResponseManager and perform action on the change in status.

Scala
// subscribe to the status of original command received and publish the state when its status changes to
// Completed
commandResponseManager.subscribe(
  controlCommand.runId, {
    case Completed(_) ⇒
      currentStatePublisher.publish(
        CurrentState(controlCommand.source, StateName("testStateName"), Set(choiceKey.set(longRunningCmdCompleted)))
      )
    case _ ⇒
  }
)
Java
// subscribe to the status of original command received and publish the state when its status changes to
// Completed
commandResponseManager.jSubscribe(subCommand.runId(), commandResponse -> {
    if (commandResponse instanceof CommandResponse.Completed) {
        Key<String> stringKey = JKeyType.StringKey().make("sub-command-status");
        CurrentState currentState = new CurrentState(sc.source().prefix(), new StateName("testStateName"));
        currentStatePublisher.publish(currentState.madd(stringKey.set("complete")));
    } else {
        // do something
    }
});