Connecting Handlers with Channels

Learn how to connect message handlers using channels to build workflows

Building business workflows is essential for most applications. Whether you need fully automated processes (like image processing pipelines) or human-interactive flows (like document approval), Ecotone makes it simple by connecting message handlers through channels.

Understanding the Flow: From Handler to Handler

The key concept in Ecotone is that every message handler can be connected to other handlers using channels. Think of channels as pipes that carry messages between different parts of your application.

Step 1: Understanding Single Handlers

Let's start with a simple command handler:

#[CommandHandler('place.order')]
public function place(PlaceOrder $command): void
{
    // Place the order logic here
}

What happens behind the scenes:

  1. Ecotone creates a channel named place.order

  2. Your handler listens to this channel

  3. When you use the Command Bus, it sends messages to this channel

A single handler connected to its input channel

Step 2: Connecting Handlers Together

Here's where it gets powerful: any handler can send messages to another handler's channel. This lets you chain handlers together to create workflows.

Let's add order verification before placing the order:

Two handlers connected: verify → place order

The magic happens with outputChannelName:

How the flow works:

  1. You send PlaceOrder to verify.order channel

  2. The verify() method processes it and returns the command

  3. Ecotone automatically sends the returned command to place.order channel

  4. The place() method receives and processes it

Making Handlers Internal (Private to Workflow)

Problem: With CommandHandler, anyone can call place.order directly through the Command Bus, bypassing your verification step!

Solution: Use InternalHandler to make handlers private to your workflow:

What this means:

  • verify.order can be called via Command Bus (entry point)

  • place.order can only be reached through the workflow

  • 🔒 This ensures orders are always verified before being placed

Adding Asynchronous Processing

Sometimes you want parts of your workflow to run asynchronously (in the background). This is perfect for:

  • Heavy processing that shouldn't block the user

  • Ensuring messages aren't lost if something goes wrong

  • Scaling parts of your workflow independently

Example: Keep verification synchronous (fast feedback) but make order placement asynchronous (reliable processing):

What happens now:

  1. verify() runs immediately and returns a response

  2. The message goes to a queue/background processor

  3. place() runs later in the background

  4. If place() fails, the message can be retried

Asynchronous handlers process messages through a queue

Adding Delays and Timeouts

Asynchronous handlers can also be delayed, which is perfect for business scenarios like:

  • Giving customers time to complete actions

  • Implementing timeout behaviors

  • Scheduling follow-up actions

Example: Give customers 24 hours to pay, then automatically cancel unpaid orders:

Delayed cancellation after 24 hours

Strategy: Use events to trigger delayed actions (events allow multiple handlers to react):

Now add the delayed cancellation handler:

Timeline:

  • T+0: Order placed, event published

  • T+24h: Cancellation handler runs automatically

Controlling Workflow Flow

Stopping the Workflow

You can stop a workflow from continuing by returning null:

Enriching Messages in Workflows

Sometimes you need to add information as messages flow through your workflow. There are two approaches:

Option 1: Transform the Payload

Return a new/modified object that contains additional data:

When to use: When the additional data is core to the next step's logic.

Option 2: Add Data to Message Headers

Keep the original payload unchanged and add extra data as headers:

When to use: When you want to keep the original payload intact and add supplementary data.

Header Propagation: Headers automatically flow through your entire workflow, so any handler can access data added by previous steps.

Testing Your Workflows with Ecotone Lite

Testing workflows is crucial for ensuring your business logic works correctly. Ecotone Lite makes testing handler chains simple and straightforward.

Setting Up Tests

Testing Handler Chains

Test complete workflows from start to finish:

Testing Asynchronous Workflows

Test async workflows in synchronous mode for easier testing:

Summary: What You've Learned

You now understand the fundamentals of connecting handlers with channels in Ecotone:

Key Concepts

  • Channels: Every handler has an input channel, and can send to output channels

  • Connection: Use outputChannelName to chain handlers together

  • Privacy: Use InternalHandler to make handlers private to workflows

  • Async Processing: Add #[Asynchronous] for background processing

  • Delays: Use #[Delayed] for time-based workflows

  • Flow Control: Return null to stop workflows

  • Data Enrichment: Transform payloads or add headers

Last updated

Was this helpful?