Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Examples of non-repeatable workflows are often used in AppFacets.

Jira Legacy
showSummaryfalse
serverJIRA (mqidentity.atlassian.net)
serverId77fb3325-4051-36d9-bcc7-761f62050707
keyDOCS-36

Code Block
languagexml
titleNon-repeatable workflow example
linenumberstrue
<AppFacet name="CSVLoader">
    <String name="destModelName" />
    <String name="DriverId" />
    <String name="ParkingLotId" />
    <String name="fileName" KnownBy="csvLoaderAc" Update="auto" />
    <Action name="csvLoaderAc" documentation="Data Facet to load CSV Data">
        <Workflow Limit="1" Live="1" Timeout="-1">
            <Task name="Main">
                <Event name="Argument" as="ActionArgument" />
                <Invoke name="CSVDataLoader" waitFor="Argument">
                    <FacetScript>
                        <Log Message="Loading file..."/>
                        <LoadFromCSV fileName="[%:Event.Argument.fileName.Value:%]" 
                                     destModelName="[%:Event.Argument.destModelName.Value:%]"
                                     DriverId="[%:Event.Argument.DriverId.Value:%]"
                                     ParkingLotId="[%:Event.Argument.ParkingLotId.Value:%]" />
                        <Log Message="Loading complete!!!"/>
                    </FacetScript>
                </Invoke>
                <Output name="ActionResult">
                    <Value>
                        <Log Message="Output file name: [%:Event.Argument.fileName.Value:%]"/>
                        <fileName>[%:Event.Argument.fileName.Value:%]</fileName>
                    </Value>
                </Output>
            </Task>
        </Workflow>
    </Action>
</AppFacet>

...

Code Block
languagexml
titleRepeatable workflow example
linenumberstrue

<ThingFacet Name="TempFacetSerial">
    <Number Name="tempValue" update="auto" KnownBy="SerialReadAction" />
    <String Name="unit" default="Celsius" Documentation="Celsius or Fahrenheit" />
    <String Name="peripheral" />
    <String Name="interfacePort" />
    <String Name="interface" />
    <String Name="uniqueId" default="56789" />
    <String Name="baudrate" />
    <String Name="format" default="ascii" />
    <String Name="operation" />
    <String Name="payload" />

    <Action Name="SerialReadAction" Documentation="Start the serial port">
        <Workflow Limit="1" Live="1" Timeout="-1">
            <Task name="Main" while="true">
                <Event name="Argument" as="ActionArgument" />

                <Invoke name="InvokeSerialRead" waitFor="Argument" get="perif://">
                    <Message>
                        <Value>
                            <InterfacePort>"[%:Event.Argument.interfacePort.Value:%]"
                            </InterfacePort>
                            <Baudrate>"[%:Event.Argument.baudrate.Value:%]"</Baudrate>
                            <Interface>"[%:Event.Argument.interface.Value:%]"</Interface>
                            <UniqueId>"[%:Event.Argument.uniqueId.Value:%]"</UniqueId>
                            <Operation>"[%:Event.Argument.operation.Value:%]"</Operation>
                            <format>"[%:Event.Argument.format.Value:%]"</format>
                            <Payload>"[%:Event.Argument.payload.Value:%]"</Payload>
                            <Peripheral>"[%:Event.Argument.peripheral.Value:%]"</Peripheral>
                        </Value>
                    </Message>
                </Invoke>
                <Output name="Result" as="ActionResult">
                    <Value>
                        <tempValue>
                            [%:Invoke.InvokeSerialRead.Message.Value/number(
                            substring-before(substring-after("[%:Invoke.InvokeSerialRead.Message.Value:%]",
                            '#TCB:'), '#')):%]
                        </tempValue>
                    </Value>
                </Output>

            </Task>
        </Workflow>
    </Action>
</ThingFacet>

...

Instances of such workflow are started right after they are created. This is done by ensuring that all the input values of the workflow's initial task(s) have their values assigned in your source code (versus waiting for external events to give value). They are only useful if they are doing something  or communicating with some other entities [en-masse] which is difficult with non-repeatable workflows.jira

Code Block
language

...

Code Block
languagexml
titleExample of non-waiting workflow
linenumberstrue
Placeholder for example of non-waiting workflow

b. Externally-activated workflows

These are workflows which have explicit “event handler”. Instances of these workflows wait for the external event to come and then start ("external" here means external to the workflow itself). The "event handler" is written as "Event" in the workflow definition. In ThingFacet (and AppFacet) workflows, the Event is typically the ActionArgument, which is triggered by the modification of actionable attributes of the model facet.

Jira Legacy
showSummaryfalse
serverJIRA (mqidentity.atlassian.net)
serverId77fb3325-4051-36d9-bcc7-761f62050707
keyDOCS-36

Code Block
languagexml
titleExample of externally-activated workflow
linenumberstrue
Placeholder for example of externally-activated workflows.

Externally-continued versus internally continued workflows

a. Externally-continued workflows

These have an invoke with the WaitFor modifier. Instances of such workflows can start, work for a while and then suspend and wait for an event in the middle of task (on the waitFor). Once wait is completed they continue until the next WaitFor or process completion (The "external" here means external to the workflow itself).

Jira Legacy
showSummaryfalse
serverJIRA (mqidentity.atlassian.net)
serverId77fb3325-4051-36d9-bcc7-761f62050707
keyDOCS-36

Code Block
languagexml
titleExample of externally-continued workflow
linenumberstrue
Placeholder for example of externally-continued workflow

b. Internally continued workflows

Instances of these workflows suspend on pipeline operations. Conceptually it’s the same as waiting for a response after an HTTP request, only without the actual request. RFID reader is an example. The process starts by itself or by an external event, but then suspends on the pipeline operation. Once a “response” is received from the device, the process continues to the next suspension or completion. The "internal" here means the pipeline operations is internal to the workflow itself. "Internal" is not related to the source of the "response". For example, the response may come from a device outside the application.

In such workflows, it is a good practice to have a Timeout modifier on the workflow.

 

Workflow instances run on top of pipelines, that is, they use pipelines to be instantiate, trigger or communicate. We call the pipeline that instantiate a workflow instance the originating pipeline. Based on the relationship between the workflow and its originating pipeline, workflow can be categorized into non-repeatable workflows and repeatable workflows.

In non-repeatable workflow, the originating pipeline waits until the workflow completes. In repeating working, the originating pipeline does not wait. The workflow, after being instantiated, may be triggered by a different pipeline.
Expand
titleunused notes
Info
iconfalse
xml

...

titleExample of non-waiting workflow
linenumberstrue
<Action name="SetOutput">
  <Workflow Limit="1" Live="1" Timeout="-1">
    <Task name="Step1">
      <Input name="Argument" type="string" kind="literal" value="Hello World!"/>
      <Output name="Result" type="string" value="Step1 says '[:Input.Argument:]'"/>
    </Task>
    <Task name="Step2">
      <Input name="Argument" type="string" value="Step1.Result"/>
      <Output name="Result" type="string" value="Step2 says that '[:Input.Argument:]'"/>
    </Task>
    <Task name="Step3">
      <Input name="Argument" type="string" value="Step2.Result"/>
      <Output name="Result" type="string" value="Step3 says that '[:Input.Argument:]'"/>
    </Task>
    <Task name="Step4">
      <Input name="Argument" type="string" value="Step3.Result"/>
      <Output name="Result" type="string" value="Step4 says that '[:Input.Argument:]'"/>
    </Task>
  </Workflow>
</Action>

b. Externally-activated workflows

These are workflows which have explicit “event handler”. Instances of these workflows wait for the external event to come and then start ("external" here means external to the workflow itself). The "event handler" is written as "Event" in the workflow definition. In ThingFacet (and AppFacet) workflows, the Event is typically the ActionArgument, which is triggered by the modification of actionable attributes of the model facet.

Code Block
languagexml
titleExample of externally-activated workflow
linenumberstrue
<Action name="SetOutput">
  <Workflow Limit="1" Live="1" Timeout="-1">
    <Task name="Step1">
      <Event name="Argument" as="ActionArgument" />
      <Output name="Result" type="string" value="Step1 says '[:Event.Argument:]'"/>
    </Task>
    <Task name="Step2">
      <Input name="Argument" type="string" value="Step1.Result"/>
      <Output name="Result" type="string" value="Step2 says that '[:Input.Argument:]'"/>
    </Task>
    <Task name="Step3">
      <Input name="Argument" type="string" value="Step2.Result"/>
      <Output name="Result" type="string" value="Step3 says that '[:Input.Argument:]'"/>
    </Task>
    <Task name="Step4">
      <Input name="Argument" type="string" value="Step3.Result"/>
      <Output name="Result" type="string" value="Step4 says that '[:Input.Argument:]'"/>
    </Task>
  </Workflow>
</Action>

Externally-continued versus internally continued workflows

a. Externally-continued workflows

These have an invoke with the WaitFor modifier. Instances of such workflows can start, work for a while and then suspend and wait for an event in the middle of task (on the waitFor). Once wait is completed they continue until the next WaitFor or process completion (The "external" here means external to the workflow itself).

Code Block
languagexml
titleExample of externally-continued workflow
linenumberstrue
<Action Name="SerialReadAction" Documentation="Start the serial port">
  <Workflow Limit="1" Live="1" Timeout="-1">
    <Task name="Main" while="true">
      <Event name="Argument" as="ActionArgument" />
      <Invoke name="InvokeSerialRead" waitFor="Argument" get="perif://">
        <Message>
          <Value>
            <InterfacePort>
              "[%:Event.Argument.interfacePort.Value:%]"
            </InterfacePort>
            <Baudrate>
              "[%:Event.Argument.baudrate.Value:%]"
            </Baudrate>
            <Interface>
              "[%:Event.Argument.interface.Value:%]"
            </Interface>
            <UniqueId>
              "[%:Event.Argument.uniqueId.Value:%]"
            </UniqueId>
            <Operation>
              "[%:Event.Argument.operation.Value:%]"
            </Operation>
            <format>
              "[%:Event.Argument.format.Value:%]"
            </format>
            <Payload>
              "[%:Event.Argument.payload.Value:%]"
            </Payload>
            <Peripheral>
              "[%:Event.Argument.peripheral.Value:%]"
            </Peripheral>
          </Value>
        </Message>
      </Invoke>
      <Log
           Message="Invoke --> [%:Invoke.InvokeSerialRead.Message.Value.received:%]" />
      <Output name="Result" as="ActionResult">
        <Value>
          <tempValue>
            [%:Invoke.InvokeSerialRead.Message.Value/number(
            substring-before(substring-after("[%:Invoke.InvokeSerialRead.Message.Value:%]",
            '#TCB:'), '#')):%]
          </tempValue>
        </Value>
      </Output>
    </Task>
  </Workflow>
</Action>

b. Internally continued workflows

Instances of these workflows suspend on pipeline operations. Conceptually it’s the same as waiting for a response after an HTTP request, only without the actual request. RFID reader is an example. The process starts by itself or by an external event, but then suspends on the pipeline operation. Once a “response” is received from the device, the process continues to the next suspension or completion. The "internal" here means the pipeline operations is internal to the workflow itself. "Internal" is not related to the source of the "response". For example, the response may come from a device outside the application.

In such workflows, it is a good practice to have a Timeout modifier on the workflow.

Code Block
languagexml
titleExample for Internally continued workflows
<ThingFacet Name="PhidgetRFID">
  <Sid Name="RFIDId" />
  <String Name="ReadTag" Update="auto" KnownBy="PhidgetReadRFIDTagAc" />
  <String Name="WriteTag" KnownBy="PhidgetWriteRFIDTagAc" />
  <String Name="RFIDURL" Default="phid://" />
  <String Name="InterfaceType" />
  <String Name="InterfaceIndex" />
  <Unique Name="RFIDIndex" Value="InterfaceIndex" />
  <DateTime Name="timestamp" Format="$SimpleDateFormat(yyyy-MM-dd'T'HH:mm:ss'Z')" />
  <AA>
    [:#o#Output.ActionArgument:]
  </AA>
  <Action Name="PhidgetReadRFIDTagAc" Documentation="Read the Tag Automatically in the vicinity">
    <Workflow Limit="1" Live="1" Timeout="-1">
      <Task name="Main" while="true">
        <Event name="Argument" as="ActionArgument" />
        <Invoke name="ReadValue" waitFor="Argument"
                get="[%:Event.Argument.RFIDURL.Value:%]" SerialNumber="[%:Event.Argument.InterfaceIndex.Value:%]"
                DeviceType="[%:Event.Argument.InterfaceType.Value:%]" />
        <Output name="Result" as="ActionResult">
          <Value>
            <ReadTag>
              [%:[%:@Output:%]Invoke.ReadValue.Message.Value:%]
            </ReadTag>
          </Value>
        </Output>
      </Task>
    </Workflow>
  </Action>
  <Action Name="PhidgetWriteRFIDTagAc" Documentation="Write the Tag Value to RFID in the vicinity">
    <Workflow Limit="1" Live="1" Timeout="-1">
      <Task name="Main" while="true">
        <Output name="ActionArgument" as="ActionArgument" />
        <Invoke name="WriteValue" waitFor="ActionArgument"
                skip-if="[%:[:AA:].WriteTag/no-value(Value):%]" post="[%:[:AA:].RFIDURL.Value:%]"
                SerialNumber="[%:[:AA:].InterfaceIndex.Value:%]"
                SensorType="WriteTag" DeviceType="[%:[:AA:].InterfaceType.Value:%]">
          <Message Type="text" Value="[%:[:AA:].WriteTag.Value:%]" />
        </Invoke>
        <Output name="Result" as="ActionResult">
          <Value>
            <WriteTag>
              [%:[%:@Output:%]Invoke.WriteValue.Message.Value:%]
            </WriteTag>
          </Value>
        </Output>
      </Task>
    </Workflow>
  </Action>
</ThingFacet>