Skip to content

Commit

Permalink
Documenting bpmnDsl and worker.
Browse files Browse the repository at this point in the history
  • Loading branch information
pme123 committed Dec 6, 2024
1 parent a7eecd5 commit 1d77e01
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 5 deletions.
106 changes: 104 additions & 2 deletions 00-documentation/src/docs/bpmnDsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ object MyProcess extends CompanyBpmnProcessDsl:
)
end MyProcess
```
Next to the _In_ and _Out_ classes we have an _InitIn_ and _InConfig_ class.
Next to the _In_ and _Out_ classes we have an _InitIn_- and _InConfig_ class.

### InitIn
Each process has an _InitWorker_ that is the first worker that is called when the process is started.
Expand All @@ -106,6 +106,7 @@ Use this class to:
- init the _Process Variables_ that are needed in the process (e.g. counters, variables used in expressions that must be defined (Camunda 7 restriction)).
- init the _Process Variables_ with default values, that are not provided by the client.
So you can be sure that they are always set - from Option to required in the process.
- extract some information from the input variables to simplify the process.

### InConfig
These are technical _Process Variables_, like:
Expand All @@ -114,7 +115,8 @@ These are technical _Process Variables_, like:

@:callout(info)
The _InitWorker_ will automatically put these variables on the process.
That means you can override them for example in _Postman_.
That means you can override them for example in _Postman_
- just set them as _process variables_ (`inConfig` object is not needed).
@:@

## Business Rule Tasks (Decision DMNs)
Expand Down Expand Up @@ -215,6 +217,106 @@ end MyUserTask
- The `In` object are the input variables you expect for the UI-Form of the _UserTask_.
- The `Out` object are the process variables, the UI-Form sends, when it completes the _UserTask_.

## External Task
An _External Task_ describes a worker.
We distinguish different types of Tasks, which are described in the next subchapters.

```scala
### Custom Task
A _Custom Task_ is a description for a worker that does some business logic, like mapping.

In General, you can do whatever you want with a _Custom Task_. See also _CustomWorker_.

```scala
object MyCustomTask extends CompanyBpmnCustomTaskDsl:

val topicName = "mycompany-myproject-myprocessV1.MyCustomTask"
val descr: String = "my custom task..."

case class In(...)
object In:
given ApiSchema[In] = deriveApiSchema
given InOutCodec[In] = deriveInOutCodec

case class Out(...)
object Out:
given ApiSchema[Out] = deriveApiSchema
given InOutCodec[Out] = deriveInOutCodec

lazy val example = customTask(
In(),
Out()
)
end MyCustomTask
```

### Init Task
An _Init Task_ is a description for a worker that initializes a _Process_.

In General, you map the `In` object to the `InitIn` object like init process variables.
See also _InitWorker_.

So no extra BPMN Element is needed for this, it is automatically defined by the _Process_.

```scala
object MyProcess extends CompanyBpmnProcessDsl:
...
case class In(
...
inConfig: Option[InConfig] = None
) extends WithConfig[InConfig]
...
case class InitIn(...)
...
end MyProcess
```

### Service Task
A _Service Task_ is a description for a worker that provides a REST API request.

See also _ServiceWorker_.

```scala
object MyServiceTask extends CompanyBpmnServiceTaskDsl:

val topicName = "mycompany-myproject-myservicetask"
val descr: String = "my service task..."
val path = "POST: /myService"

type ServiceIn = MyServiceBody
type ServiceOut = NoOutput
lazy val serviceInExample = MyServiceBody()
lazy val serviceMock = MockedServiceResponse.success204

case class In(...)
object In:
given ApiSchema[In] = deriveApiSchema
given InOutCodec[In] = deriveInOutCodec

case class Out(...)
object Out:
given ApiSchema[Out] = deriveApiSchema
given InOutCodec[Out] = deriveInOutCodec

lazy val example = serviceTask(
In(),
Out(),
serviceMock,
serviceInExample
)
end MyServiceTask
```
This task is more specific, and so we need to define
- The method and the path of the REST service for the documentation.
- The _ServiceIn_ and _ServiceOut_ types.
They represent the bodies of the service-request and -response.
- In the _example_ we define also the _serviceInExample_ and the _serviceMock_.

@:callout(info)
At the moment we only support these 3 types of _External Tasks_.
Depending on the use case we can add more types.
@:@

## Receive Message Event
A _Receive Message Event_ represents a catching message event.
The input defines the message you expect.
Expand Down
142 changes: 139 additions & 3 deletions 00-documentation/src/docs/functionalityDsls/worker.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,146 @@
# Workers
The implementation of an **_External Task_** is done by a _**Worker**_.

So for each _External Task_ type we have a DSL for an according _Worker_.

## Custom Worker
The _Custom Worker_ is a general _Worker_ that can used for any business logic or integration.

It automatically does:
- validate the input variables

You can create:
- business logic that can't be handled by the expression language in the BPMN itself
- a service integration that is not covered by the _Service Worker_
- whatever you want

```scala
import mycompany.myproject.bpmn.myprocess.v1.MyCustomTask.*

@Configuration
class MyCustomTaskWorker extends CompanyCustomWorkerDsl[In, Out]:

lazy val customTask = example

def runWork(in: In): Either[CamundalaWorkerError.CustomError, Out] =
// your business logic
???
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
??? // custom validation logic here
```
- `lazy val customTask` is just needed for the compiler to check the correctness of the types.
- `runWork` is the method that is called by the _Worker_ to execute the business logic.
- The code can either:
- complete the task successfully with a result -> `Right[Out]`
- fail the task with an error -> `Left[CamundalaWorkerError.CustomError]`
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
If the validation fails, the process will fail.

Examples:

### runWork
TODO
### validate
This is the same in every worker type.
TODO

```scala
## Init Process Worker
The _Init Process Worker_ is a special _Worker_ that is used to start a process.

It automatically does:
- validate the input variables
- merge the _inConfig_ variables with manual overrides

You can:
- init input process variables with default values.
- init process variables used to control the process flow,
like counters, variables that may not be on the process.
- create simplified process variables to simplify the process flow.
- validate the input variables, if you need more sophisticated validation logic,
than you can do with the type definition.

```scala
import mycompany.myproject.bpmn.myprocess.v1.MyProcess.*

@Configuration
class MyProcessWorker extends CompanyInitWorkerDsl[In, Out, InitIn, InConfig]:

lazy val inOutExample = example

def customInit(in: In): InitIn =
??? // init logic here
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
??? // custom validation logic here
```
- `lazy val inOutExample` is just needed for the compiler to check the correctness of the types.
- `customInit` is the method that is called by the _Worker_ to execute the init logic.
- The method sets the process variables according the _InitIn_ object.
Be aware that this can not fail, as the input variables are already validated.
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
If the validation fails, the process will fail.

Examples:

### customInit
TODO

## Service Worker
TODO
The _Service Worker_ is a special _Worker_ that is used to call a REST API service.

## Custom Worker
TODO
It automatically does:
- validate the input variables

You can provide:
- the method and the path of the service
- the query parameters
- the headers
- the mapping of the input- or output request body

```scala
import mycompany.myproject.bpmn.myprocess.v1.MyServiceTask.*

@Configuration
class MyServiceTaskWorker extends CompanyServiceWorkerDsl[In, Out]:

lazy val serviceTask = example

def apiUri(in: In) = uri"$serviceBasePath/myService"
override protected lazy val method: Method = Method.POST

override protected def inputHeaders(in: In): Map[String, String] =
??? // map the input variables to the headers
override def querySegments(in: In) =
??? // map the input variables to the query parameters
override def inputMapper(in: In): Option[ServiceIn] =
??? // map the input variables to the service request body
override def outputMapper(
out: ServiceResponse[ServiceOut],
in: In
): Either[ServiceMappingError, Out] =
??? // map the service response body and header to the output variables
override def validate(in: In): Either[CamundalaWorkerError.ValidatorError, In] =
??? // custom validation logic here
```
- `lazy val serviceTask` is just needed for the compiler to check the correctness of the types.
- `def apiUri(in: In)` the path of the service, with the path parameters from the `in` object.
The only required function.
- `override protected lazy val method: Method` is the HTTP method. Default is `Method.GET`.
- `override def querySegments(in: In)` is optional and can be used to add query parameters to the request.
- `override def inputHeaders(in: In)` is optional and can be used to add headers to the request.
- `override def inputMapper(in: In)` is optional and can be used to map the input variables to the request body.
- `override def outputMapper(out: ServiceResponse[ServiceOut], in: In)` is optional and can be used to map the response body and -headers to the output variables.
- `override def validate(in: In)` is optional and can be used to add more sophisticated validation logic.
If the validation fails, the process will fail.

Examples:

### apiUri
TODO
### querySegments
TODO
### inputHeaders
TODO
### inputMapper
TODO
### outputMapper

0 comments on commit 1d77e01

Please sign in to comment.