.. _tasks: Task Arbitration ================ .. _TaskState: http://docs.cor-lab.de//rst-manual/trunk/html/generated/stable/package-rst-communicationpatterns.html#rst.communicationpatterns.TaskState .. _Dictionary: http://docs.cor-lab.de//rst-manual/trunk/html/generated/stable/package-rst-generic.html#rst.generic.Dictionary .. _ResourceAllocation: http://docs.cor-lab.de//rst-manual/trunk/html/generated/sandbox/package-rst-communicationpatterns.html#rst.communicationpatterns.ResourceAllocation .. _Scope: http://docs.cor-lab.org/rsb-manual/trunk/html/specification-scope.html .. _RST: http://docs.cor-lab.de//rst-manual/trunk/html/index.html .. _Ini file: https://en.wikipedia.org/wiki/INI_file The task arbitration service can be used to trigger and arbitrate various simple or short lived subroutines of the apartment, aka tasks. Tasks can be executed by sending `TaskState`_ objects to the following scope: ``SCOPE_TASK=/coordination/request/task/``, or by using the :ref:`buttons`. The service internally uses the :ref:`allocation` for the arbitration of parallel invocations and only accepts and executes a task if it can allocate all needed resources. The life-cycle of a single task looks like the following. The initiating component, called submitter, thereby usually only triggers the INITIATED, ABORT, and UPDATE states. The handler uses ACCEPTED or REJECTED to signal if it is able to process the task and informs if it finished successful with a COMPLETED state or sends FAILED in an error scenario. .. figure:: /images/coordination/task.png :width: 450px :figclass: align-center :alt: Task state pattern (c.f. `TaskState`_) The task state pattern that is monitored by the coordination (c.f. `TaskState`_) Tasks can be processed (handled) by an arbitrary component in the apartment that communicates via rsb. Each invokation of the task arbitration service maps an incoming request from the submitter to either another `TaskState`_, an rpc call, or a simple informer message on the handler side. In all cases, tasks are requested via a `TaskState`_ object with INITIATED as its state and SUBMITTER as its origin. The arbitration service's answer depends on the handler's implementation. In case the handler component supports task states, communication is redirected bidirectionally. Otherwise, the task is accepted immediately by the arbitration service. If the handler is an informer, it is also completed directly afterwards. In case of an rpc, it is completed after the method call returns or fails if the method times out or produces an exception. If resources are lost, the task is set to aborted in both the submitter and the handler. The following diagram depicts how tasks are arbitrated between the submitter and handler using the :ref:`allocation`: .. figure:: /images/coordination/call.png :width: 600px :figclass: align-center :alt: Call graph of tasks with resources that are available or unavailable, that are being superseded or expired. Call graph of tasks following the `TaskState`_ protocol using resources that are available or unavailable, that are being superseded or expired. Each task is mapped transparently to a `ResourceAllocation`_. Available tasks --------------- Currently, the following tasks are available: ================== ================================================================ ===================== Task Purpose Involved components ================== ================================================================ ===================== ``lighton`` light on everywhere for 10 minutes (allocates light resources) *location-light* ``lightoff`` light off everywhere for 10 minutes (allocates light resources) *location-light* ``autolight`` resume automatic light (only frees resources) *-* ``identifyperson`` identifies a person via face recognition *face id* ``elan`` displays an ELAN screenshot at the BFT *displays* ``nextinscene`` skips to the next song in the current scene's playlist :ref:`guiro` ``stopaudio`` stops audio playback :ref:`guiro` legacy (inactive) ``debug`` displays the desktop at the BFT to make grafana visible *displays* ``greet`` greeting (currently only triggers an utterance in the dialog) :ref:`dialog_manager` ``goodbye`` goodbye (currently only triggers an utterance in the dialog) :ref:`dialog_manager` ``introduction`` introduction (greet & light, list, learnperson) :ref:`dialog_manager` ``list`` scenario listing (short explanation) :ref:`dialog_manager` ``explain`` scenario explanation (long/with commands) :ref:`dialog_manager` ================== ================================================================ ===================== Task specification ------------------ All available tasks are read from a configuration file that resides inside the `main coordination repository `_. If you want to add a new task, you have to create a new `Ini file`_ containing an optional **[resources]** and a single **[remote]** section. These files are evaluated at runtime and trigger the remote after the resources have been allocated sucessfully. Remotes can be specified as inofmer, task, or rpc and given a payload. The following code-block illustrates an example task with the default resources that are allocated and an rpc handler. Please refer to :ref:`resource_ini` for an overview of allowed values for the **[resources]** section. .. code-block:: INI [resources] ; these are the default values for task resources policy=MAXIMUM priority=NORMAL initiator=HUMAN duration=10000 ids=/coordination/request/task/ description="task: " [remote] ; these are the default values for delay/timeout delay=0 timeout=5000 ; example values below type=rpc scope=/home/living/hometheater/display/tv/ctrl/showImage payload='file:///vol/csra/releases/xenial/lsp-csra-rc/share/adhoc_res/elan.png' A **[remote]** section specifies an interaction with another component via `TaskState`_, remote procedure call (rpc), or simple message (informer). Types, scopes, and payloads are mandatory for a remote seciton. The **scope** field has to follow the RSB `Scope`_ definition. The **type** field can be any of *task*, *rpc*, or *informer*. The **payload** are evaluated as numbers, booleans, or `RST`_ data types. Additionally, all these parameters can be overridden by using a `Dictionary`_ as the `TaskState`_ payload when requesting a scene. **delay** and **timeout** fields are optional, default to *0* and *5000* and are evaluated as millisecond values. In contrast to tasks, in :ref:`scenes ` multiple remote sections can be specified. Examples -------- The following example works with pure RSB/RST and do not need an additional library. .. code-block:: java // Import the following: import com.google.protobuf.ByteString; import rsb.*; import rst.communicationpatterns.TaskStateType.TaskState; Initiate a task (enable the automatic light) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: java :emphasize-lines: 3 // RSB Informer Informer informer = Factory.getInstance(). createInformer("/coordination/request/task/autolight"); informer.activate(); // create a task state TaskState.Builder taskBuilder = TaskState.newBuilder() .setOrigin(TaskState.Origin.SUBMITTER) .setState(TaskState.State.INITIATED) .setSerial(1) .setPayload(ByteString.EMPTY) .setWireSchema(ByteString.copyFromUtf8("utf-8-string")); // send the task state informer.send(taskBuilder.build()); Check whether the task has been carried out successfully ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: java :emphasize-lines: 2, 15, 18, 26 // RSB Listener Listener listener = Factory.getInstance().createListener("/coordination/request/task/autolight"); listener.activate(); // Add a local event handler listener.addHandler(new Handler(){ @Override public void internalNotify(Event event) { // Only handle task state types if (event.getData() instanceof TaskState) { TaskState taskState = (TaskState) event.getData(); // Only regard tasks that originate from the handler (i.e., the arbitration) if (taskState.getOrigin().equals(TaskState.Origin.HANDLER)) { // Investigate payload: print out content if string if (taskState.getWireSchema().equals(ByteString.copyFromUtf8("utf-8-string"))) { String payloadStr = (String) taskState.getPayload().toStringUtf8(); System.out.println("message content: " + payloadStr); } else { System.out.println("other message content"); } // Investigate state switch(taskState.getState()){ case REJECTED: System.out.println("Task execution refused."); break; case ABORTED: System.out.println("Task aborted (externally)."); break; case FAILED: System.out.println("Task failed (component)."); break; case COMPLETED: System.out.println("Task successful."); break; } } } } }, true);