Skip to content

Microservice orchestration

HTTP service chain

A common pattern: call a series of HTTP endpoints where each step uses output from the previous one. No custom workers needed — Conductor handles it with built-in HTTP tasks.

{
  "name": "order_processing",
  "description": "Validate order, charge payment, reserve inventory, send confirmation",
  "version": 1,
  "schemaVersion": 2,
  "inputParameters": ["orderId", "customerId", "amount", "items"],
  "tasks": [
    {
      "name": "validate_order",
      "taskReferenceName": "validate",
      "type": "HTTP",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/orders/${workflow.input.orderId}/validate",
          "method": "POST",
          "body": {
            "customerId": "${workflow.input.customerId}",
            "items": "${workflow.input.items}"
          },
          "connectionTimeOut": 5000,
          "readTimeOut": 5000
        }
      }
    },
    {
      "name": "charge_payment",
      "taskReferenceName": "payment",
      "type": "HTTP",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/payments/charge",
          "method": "POST",
          "body": {
            "orderId": "${workflow.input.orderId}",
            "amount": "${workflow.input.amount}",
            "customerId": "${workflow.input.customerId}"
          },
          "connectionTimeOut": 10000,
          "readTimeOut": 10000
        }
      }
    },
    {
      "name": "reserve_inventory",
      "taskReferenceName": "inventory",
      "type": "HTTP",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/inventory/reserve",
          "method": "POST",
          "body": {
            "orderId": "${workflow.input.orderId}",
            "items": "${workflow.input.items}",
            "paymentId": "${payment.output.response.body.paymentId}"
          },
          "connectionTimeOut": 5000,
          "readTimeOut": 5000
        }
      }
    },
    {
      "name": "send_confirmation",
      "taskReferenceName": "notify",
      "type": "HTTP",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/notifications/send",
          "method": "POST",
          "body": {
            "customerId": "${workflow.input.customerId}",
            "orderId": "${workflow.input.orderId}",
            "paymentId": "${payment.output.response.body.paymentId}",
            "reservationId": "${inventory.output.response.body.reservationId}"
          }
        }
      }
    }
  ],
  "outputParameters": {
    "paymentId": "${payment.output.response.body.paymentId}",
    "reservationId": "${inventory.output.response.body.reservationId}"
  },
  "failureWorkflow": "order_compensation",
  "timeoutPolicy": "TIME_OUT_WF",
  "timeoutSeconds": 120
}

Each task passes data forward using ${taskReferenceName.output.response.body.field} expressions. If any step fails, Conductor retries it (configurable) and can trigger the failureWorkflow for compensation.

Register and run:

curl -X POST 'http://localhost:8080/api/metadata/workflow' \
  -H 'Content-Type: application/json' \
  -d @order_processing.json

curl -X POST 'http://localhost:8080/api/workflow/order_processing' \
  -H 'Content-Type: application/json' \
  -d '{"orderId": "ORD-123", "customerId": "CUST-456", "amount": 99.99, "items": ["SKU-A", "SKU-B"]}'

HTTP with conditional branching

Use a SWITCH operator to route workflow execution based on a previous task's output.

{
  "name": "user_onboarding",
  "version": 1,
  "schemaVersion": 2,
  "inputParameters": ["userId"],
  "tasks": [
    {
      "name": "get_user_profile",
      "taskReferenceName": "profile",
      "type": "HTTP",
      "inputParameters": {
        "http_request": {
          "uri": "https://api.example.com/users/${workflow.input.userId}",
          "method": "GET"
        }
      }
    },
    {
      "name": "route_by_tier",
      "taskReferenceName": "tier_switch",
      "type": "SWITCH",
      "evaluatorType": "javascript",
      "expression": "$.tier == 'enterprise' ? 'enterprise' : 'standard'",
      "inputParameters": {
        "tier": "${profile.output.response.body.tier}"
      },
      "decisionCases": {
        "enterprise": [
          {
            "name": "assign_account_manager",
            "taskReferenceName": "assign_am",
            "type": "HTTP",
            "inputParameters": {
              "http_request": {
                "uri": "https://api.example.com/account-managers/assign",
                "method": "POST",
                "body": {"userId": "${workflow.input.userId}"}
              }
            }
          }
        ],
        "standard": [
          {
            "name": "send_welcome_email",
            "taskReferenceName": "welcome",
            "type": "HTTP",
            "inputParameters": {
              "http_request": {
                "uri": "https://api.example.com/emails/welcome",
                "method": "POST",
                "body": {"userId": "${workflow.input.userId}"}
              }
            }
          }
        ]
      }
    }
  ]
}

Parallel HTTP calls with Fork/Join

When tasks are independent, run them in parallel with a static fork.

{
  "name": "enrich_customer_data",
  "version": 1,
  "schemaVersion": 2,
  "inputParameters": ["customerId"],
  "tasks": [
    {
      "name": "parallel_enrichment",
      "taskReferenceName": "fork",
      "type": "FORK_JOIN",
      "forkTasks": [
        [
          {
            "name": "get_credit_score",
            "taskReferenceName": "credit",
            "type": "HTTP",
            "inputParameters": {
              "http_request": {
                "uri": "https://api.example.com/credit/${workflow.input.customerId}",
                "method": "GET"
              }
            }
          }
        ],
        [
          {
            "name": "get_purchase_history",
            "taskReferenceName": "purchases",
            "type": "HTTP",
            "inputParameters": {
              "http_request": {
                "uri": "https://api.example.com/purchases/${workflow.input.customerId}",
                "method": "GET"
              }
            }
          }
        ],
        [
          {
            "name": "get_support_tickets",
            "taskReferenceName": "tickets",
            "type": "HTTP",
            "inputParameters": {
              "http_request": {
                "uri": "https://api.example.com/support/${workflow.input.customerId}",
                "method": "GET"
              }
            }
          }
        ]
      ]
    },
    {
      "name": "join_results",
      "taskReferenceName": "join",
      "type": "JOIN",
      "joinOn": ["credit", "purchases", "tickets"]
    }
  ],
  "outputParameters": {
    "creditScore": "${credit.output.response.body}",
    "purchases": "${purchases.output.response.body}",
    "tickets": "${tickets.output.response.body}"
  }
}

All three HTTP calls execute simultaneously. The JOIN waits for all to complete before the workflow continues.