Services are domain-related classes that implement valuable methods, called tasks in Infinitic terminology. Typical self-explanatory examples are:
Services are exposed through our Apache Pulsar cluster by workers.
As illustrated above:
- one worker can contain multiple instances of the same service. This is useful for a worker to run multiple tasks in parallel.
- the same service can be deployed through multiple workers. This is useful to scale the service horizontally and ensure resiliency to the failure of a worker.
A worker can also contain different services if needed.
A task is a service's method. It can be
- a database call;
- an API call;
- a complex domain-driven action;
- actually anything!
Tasks are processed inside workers and remotely invoked through Apache Pulsar.
Currently, we can write services in Java or Kotlin only. Infinitic could support more programming languages later. It already has some experimental workers running in Node.js.
A worker is a running application connected to our Apache Pulsar cluster and configured to run one or multiple services. For each service that it contains, a worker does:
- listen to the Apache Pulsar's topic dedicated to the service;
- consume and deserialize their messages and process tasks accordingly;
- send back the serialized results.
Workers are stateless and can be scaled horizontally.
When using Infinitic, we do not need to know anything about the messages exchanged between services and workflows. Infinitic handles that for us. under the hood, workers receive
ExecuteTask command messages (with task's details) and return
TaskCompleted (with task's result) or
TaskFailed (with task's error) event messages. When using a choreography pattern, services need to know the events produced by other services. This is not the case here as we use an orchestration pattern. Services are fully decoupled.
A workflow is a special service dedicated to orchestrating the execution of different tasks (or sub-workflows) according to an execution logic directly described in its methods. Infinitic does not define workflows through JSON or Yaml files but with imperative code, following a modern workflow as code pattern.
Workers running workflows are also stateless and can be scaled horizontally. They connect to a database storing the state of each workflow instance. Infinitic automatically maintains those states as workflow executions progress.
Today, supported databases are Redis and MySQL. Adding another database is trivial; please contribute. Soon, workflow services could be deployed as Pulsar stateful functions, removing the need to manage another database.
Contrary to "normal" services, each workflow instance has its own message consumer using a key-shared subscription on workflow's ID to ensure that all messages related to the same workflow instance are handled sequentially. This is needed to:
- avoid race conditions induced by parallel handling of multiple messages related to the same workflow instance
- maintain locally a cache of the workflow state
- avoid race conditions when saving workflow state in the database
We use a client mainly to start new workflow instances. To do so, clients need to know the signature of workflow services and be able to connect to our Apache Pulsar cluster.