Orchestrator Service
The OS1 Orchestrator allows developers to automate and manage workflows across multiple distributed components. With the orchestrator, you can define custom business logic, create workflows, and automate the sequence of actions across various distributed components, all through a simple API integration.
This guide will walk you through:
- What you can achieve with the Orchestrator
- Real-world use cases for common workflows
- Step-by-step instructions for setting up and integrating the Orchestrator into your system
Example: Order Processing
Let’s consider a scenario: When a new order is placed, multiple tasks need to happen at once:
- Validate the shipping address
- Encode customer information (e.g., phone number)
- Generate a work order
- Schedule a pickup
Traditionally, this would require complex, tightly-coupled code across multiple services. The Orchestrator simplifies this by providing a flexible, event-driven workflow management system.
Similarly, you can use the Platform Orchestrator for some of the given common scenarios in the Example section.
- By using OS1, you can automate workflows that span multiple microservices, saving time, reducing complexity, and providing customization capability for each tenant. The Orchestrator enables you to:
- Create a single system that can handle multiple business use cases
- Customize workflows for each tenant without changing core system architecture
- Break complex processes into configurable, reusable components
- Coordinate actions across multiple microservices
- Define custom plugins for specific business logic
- Create event-driven automated processes
- Offers scalability by managing workflows across multiple services with minimal manual intervention.
To start using OS1 Orchestrator, you’ll need to integrate its key components—Plugins, Workflows, and Rules—into your system. The following sections will guide you through setting up your API access, configuring workflows, and automating your processes with real-world examples.
Before you start using an OS1 Orchestrator, ensure you have:
- Access to OS1 Orchestrator API (you will need your API keys and credentials). (link to authentication)
- Your application where you want to integrate the orchestrator
Orchestrator contains three main building blocks: Plugins, Workflow, Rules.
A Plugin is a custom code module that executes tenant-specific or custom business logic that has to be written and hosted by the App developer. Plugins are where the actual work happens. Each plugin is a piece of code that does one specific task. A tenant can host his own set of plugins that contains tenant specific code and business logic and integrate it with the OS1 orchestrator. Currently, you need an HTTPs API to configure the plugin with OS1. Plugins allow you to:
- Implement custom business rules
- Define specific actions for different events
- Integrate unique tenant requirements
A Workflow is an ordered set of plugins that executes the plugins in a specific sequence—pre, main, and post—according to their priority.
- Pre: A plugin that runs before the main logic
- Main: The primary business logic plugins
- Post: Plugins that run after the main workflow
A rule determines which workflow can be executed based on the specific event generated in OS1. For eg: You can configure a plugin workflow for Encoding phone number, Encoding address, etc and map it against the order created Event.
- Step-by-step instructions for integrating.
- Clear code examples and explanations for each step.
- Screenshots or diagrams to illustrate key points.
To integrate Orchestrator with your apps or services, you need to set up Orchestrator service.
For an Order processing scenario, the Orchestrator service is enabled by default and does not require additional configuration.
Note: If you are using the Entity or Participant services, the Orchestrator must be explicitly enabled. Refer to their Swagger documentation for detailed API configurations to enable and utilize the Orchestrator in these cases.
Plugins are custom code modules that perform specific actions in response to events. When an event occurs (such as a new order being placed), plugins define what should happen—like encoding a phone number or validating a shipping address.
Attribute | Description | Requirement |
---|---|---|
name | Unique name for the plugin | 3-50 characters, alphanumeric |
httpUrl | Endpoint to be called when the plugin executes | Valid HTTPS URL |
httpMethod | API method for endpoint call (e.g., POST, GET) | Required |
responseType | The expected response type | SYNC or ASYNC (default: ASYNC) |
secretKey | The encryption key used for plugin calls ensures secure communication. By default, the plugin payload is HMAC-encrypted with this key and must be decoded using the same key within the plugin. Similarly, the plugin response must be encrypted using the same key. | Required |
httpRequestBodyTemplate | The template for the body of the HTTP request The OutputJsonPath specifies the key and value to be mapped to the corresponding key in the plugin's request payload. For example, "tid": " .tenantId" maps the tenantId value to the tid key in the request payload. Note: This follows JSON logic semantics for specifying the value path. | Optional, depending on your use case |
For example, you can create a plugin that encodes a phone number as part of your order processing workflow.
Example
{ "name": "encodePhonePlugin", "httpUrl": "https://api.example.com/encode-phone", "httpMethod": "POST", "httpHeaders": { "plugin": "phoneEncoder" }, "httpRequestBodyTemplate": [ { "outputJsonPath": { "tenantId": "$.tenantId", "phoneNumber": "$.order.customerPhone", "orderId": "$.orderId" } }, { "entity": "order", "input": { "tenant_id": "$.tenantId", "id": "$.orderId" }, "outputJsonPath": { "encodedPhone": "$.encodedPhone" } } ], "requestTimeout": 5, "responseType": "ASYNC", "secretKey": "SECRET_KEY", "protocol": "HTTP" } |
---|
In this example, when a new order is created, this plugin will encode the customer's phone number.
Workflows allow you to define the sequence in which plugins should run. For example, a workflow may first validate data and then encode it.
You can define workflows for different stages (pre, main, post) depending on the sequence of operations you want to execute.
Attribute | Description | Requirement |
---|---|---|
name | Name of the workflow | Alphanumeric, 3-50 characters |
description | A short description of what the workflow does | Optional |
PluginID | ID of the plugin created in the plugin registration process | Mandatory |
Here, we're setting up an example workflow that validates and then encodes a phone number.
Example Workflow for Order Processing
{ "workflow": { "flows": { "pre": [ { "name": "validatePhonePlugin", "description": "Validates phone number format", "pluginId": "plugin:08229ce8-d2b6-5178-9d76-b946f6d2ba10" } ], "main": [ { "name": "encodePhonePlugin", "description": "Encodes customer phone number", "pluginId": "plugin:2388bbd4-59cf-5b7c-8e99-42ec039726e3" } ], "Post": [] } } } |
---|
This workflow validates the phone number first (pre-processing) and then encodes the phone number (main processing) when a new order is created.
Rules connect specific events to workflows.They determine when your workflow should run. For example, a rule might trigger a workflow when a new order is created, or when a shipment is marked as delivered.
Configuration
Attribute | Description | Requirement |
---|---|---|
name | Name of the rule | Alphanumeric, 3-50 characters, Unique |
event | The event that triggers the workflow | E.g., orderCreatedEvent |
workflow | Workflow to execute when the event occurs |
|
logic | Conditional logic for triggering the workflow | JSON logic expression |
tenantId | Tenant identifier for multi-tenant environments | Required |
Example Rule for Triggering Workflow on Order Creation:
{ "name": "OrderPhoneEncodingRule", "event": "orderCreatedEvent", "workflow": { "flows": { "main": [ { "name": "validatePhonePlugin", "description": "Validates phone number", "pluginId": "plugin:2388bbd4-59cf-5b7c-8e99-42ec039726e3" }, { "name": "encodePhonePlugin", "description": "Encodes phone number", "pluginId": "plugin:3388bbd4-89ff-467c-8e99-42ec039456g9" } ] } }, "serviceName": "orchestrator", "workflowVersion": 1, "logic": { "==": [ "$.reason", "ORDER_CREATED" ] }, "tenantId": "default" } |
---|
In this example, the rule triggers our phone encoding workflow when a new order is created.
Check Execution Status
Once your workflow is running, you'll want to monitor its execution. Use this API to check the status of your workflows and plugins.
GET https://{tenantID}.{baseurl}/core/api/v1/entityStatus/dashboard/{entityId} |
---|
Example response:
{ "entityId": "order:123", "status": "COMPLETED", "workflows": [ { "name": "OrderPhoneEncodingRule", "status": "COMPLETED", "plugins": [ { "name": "validatePhonePlugin", "status": "COMPLETED" }, { "name": "encodePhonePlugin", "status": "COMPLETED" } ] } ] } |
---|
- Orchestrating different OS1 entities
- Creating a job for a new work order
- Updating container and work order status based on job updates
- Creating the next job once the previous leg is completed, etc.
For example, in the Order and Dispatch service, the Orchestrator will handle various shipment events such as failure to deliver, shipment delivered, or the customer refusing to accept the package. The Orchestrator processes these events according to the rules. In some cases, manual intervention is required, such as when a facility manager finds a damaged package. The system will continue to create work orders for such cases until the issue is resolved and the case is closed.
For specialized scenarios like transporting hazardous chemicals, you can add custom logic to define specific routing or handling requirements. Suppose, the shipment contains hazardous chemicals that can only be transported by road. In this case, the developer can add custom logic in the app to deliver the shipment from Point A to Point B using roadways transportation.
Scenario: When a new vehicle entity is created or a participant is added (such as a customer or driver), we want to automate tasks like updating related entities (e.g., shipments, containers) or triggering notifications. The Orchestrator service will automatically handle these tasks via custom plugins when specific events occur.
First, ensure that the Orchestrator service is enabled for both entities and participants to allow event processing.
json
{ "enableOrchestrator": true } |
---|
This step ensures that the Orchestrator can listen to the relevant events and trigger the corresponding actions.
The Orchestrator listens to specific events for both entities and participants, triggering actions like plugin execution.
- EntityCreationSuccessEvent: Triggered when a new entity (e.g., vehicle) is created.
- EntityUpdationSuccessEvent: Triggered when an entity is updated.
- ParticipantCreationSuccessEvent: Triggered when a new participant (e.g., customer or driver) is added.
- UpdateParticipantSuccessEvent: Triggered when a participant’s details are updated.
Whenever a vehicle entity is created, we want to update related entities, such as shipments or containers.
The vehicle-EntityCreationSuccessEvent is triggered when a vehicle is created.
The Orchestrator executes a plugin to update related entities (shipment, container, etc.).
The plugin updates related entities with the vehicle information.
Now, let's define and register the custom plugins that will be executed when the relevant events are triggered.
The plugin registers an action to update related entities (such as shipments or containers) when the event for vehicle creation occurs.
This plugin triggers a job creation when a new event is detected. It performs tasks like updating locations and handling other relevant details.
json
{ "name": "createJobPlugin", "httpUrl": "https://delhivery.preprod.fxtrt.io/core/api/v1/jobManager/", "httpMethod": "POST", "httpHeaders": { "plugin": "jobManager" }, "httpRequestBodyTemplate": [ { "outputJsonPath": { "tenantId": "$.tenantId", "pickupLocation": "$.workOrders[0].pickupDetails.location", "deliverLocation": "$.dropDetails.location", "deliverContact": "$.dropDetails.contact", "orderId": "$.orderId", "workOrderId": "$.workOrders[0].id" } } ], "dlqOnFailure": true, "requestTimeout": 5, "callbackTimeout": 5, "responseType": "ASYNC", "secretKey": "SECRET_KEY", "protocol": "HTTP" } |
---|
To automate tasks across multiple steps, we can create plugin workflows that specify a sequence of plugins to be executed.
In this example, we create a RuleTranslatorPluginWorkflow to update both the container and work order.
{ "name": "RuleTranslatorPluginWorkflow", "description": "workflow to update container and workOrder", "tag": [ { "name": "RuleTranslatorPluginWorkflow", "value": "workflow" } ], "pre": { "plugins": [ "fetchData" ] }, "main": { "plugins": [ "ContainerRuleTranslatorPlugin", "WorkOrderRuleTranslatorPlugin" ] } } |
---|
This workflow first fetches any necessary data with the fetchData plugin, and then executes the main plugins: ContainerRuleTranslatorPlugin and WorkOrderRuleTranslatorPlugin.
Rules specify which workflows should be executed in response to specific events. For example, when a vehicle entity is created, we want to trigger the RuleTranslatorPluginWorkflow.
In this example, the rule is triggered for a CreateJobEvent, and the associated workflow is executed only if the container type is bags.
{ "name": "WorkflowInstanceCompletedEventRule", "event": "CreateJobEvent", "pluginWorkflowId": "plugin-workflow:81182a29-92f5-54a1-88a8-dd6f730a0069", "serviceName": "orchestrator", "logic": { "and": [ { "==": [ "$.container_type", "bags" ] } ] } } |
---|