Alagesan Palani

Alagesan Palani

Share this post

Alagesan Palani
Alagesan Palani
Five Go Concurrency Patterns, every Go Developer must know - Pipeline
Copy link
Facebook
Email
Notes
More
User's avatar
Discover more from Alagesan Palani
Advanced Go (Golang), practical patterns, practices and solutions in software design and architecture, Microservices, Cloud, Kubernetes and DevOps.
Already have an account? Sign in

Five Go Concurrency Patterns, every Go Developer must know - Pipeline

With an example implementation of E-Commerce Order Processing

Alagesan Palani's avatar
Alagesan Palani
Jan 01, 2025
1

Share this post

Alagesan Palani
Alagesan Palani
Five Go Concurrency Patterns, every Go Developer must know - Pipeline
Copy link
Facebook
Email
Notes
More
1
Share

This is a part of a multi-part series on Go Concurrency Patterns:

  1. Go Concurrency Patterns - Worker Pool

  2. Go Concurrency Patterns - Fan-In Fan-Out

  3. Go Concurrency Patterns - Context Cancellation

  4. Go Concurrency Patterns - Pipeline

Go Concurrency Patterns - Pipeline

The Pipeline concurrency pattern is a design paradigm where:

  1. Data flows through multiple stages, each performing a specific task.

  2. Each stage processes input, transforms it, and passes the result to the next stage.

  3. Stages run concurrently, improving throughput.

Scenario: E-Commerce Order Processing

In an e-commerce platform, consider the following workflow for processing customer orders:

  1. Order Validation: Ensure all necessary details are presentk and are valid.

  2. Inventory Check: Verify the stock availability of the ordered products.

  3. Payment Processing: Process the payment securely with a payment gateway

  4. Shipment Preparation: Prepare the items for shipping.

Problem

  • Processing above tasks sequentially can be slow, especially during peak times.

  • High concurrency with multiple independent goroutines can make error handling and task management complex.

Solution

So, we use the Pipeline concurrency pattern:

  1. Each stage is responsible for a specific step in the order processing workflow.

  2. Data (orders) flows from one stage to the next via channels.

  3. Each stage operates concurrently, improving efficiency and scalability.

Image explaining four stages and each stage manages separate input and output channel. There are four stages and five channels

Keypoint: Each stage subroutine processes an order independently/concurrently, while the rest of the stages work on its own functionality on its own order concurrently. Hence increasing throughput. However, due to sequential and queuing nature of channel ensures each order goes through the stages in the predefined order always, ie. stage1 →stage2→stage3→stage4. for example: when stage1 validates order4, stage3 performs payment for order3 and stage4 process shipping on order1 - all at once concurrently.

Important: Each stage runs in its own goroutine, allowing multiple orders to be processed simultaneously at different stages

Channels pass orders between stages, ensuring thread-safe communication.

Implementation:

Order : This object is a subset of full Order object as it does n’t have complete order detail such as order qty and price etc. this just has some order status to represent the status of the current processing stage such as Valid, Stocked, Paid, Shipped.

validateOrder : Its the first stage of the pipeline and performs: a). Takes in an input channel to read Order object from main function b). Spinup a new goroutine to run validation in a separate goroutine. c). Performs validation and marks order status as order.Valid=true or false d). publishes validated Order to an output channel (which will be sent to the next stage in the process).

checkInventory : Its the second stage of the pipeline and performs: a). Takes in an input channel (passed from previous stage) to read Order object from previous stage b). Spinup a new goroutine to run inventory checking in a separate goroutine. c). Performs stock inventory availability check and marks order status as order.Stocked=true or false d). publishes inventory checked Order to an output channel (which will be sent to the next stage in the process).

processPayment : Its the third stage of the pipeline and performs: a). Takes in an input channel (passed from previous stage) to read Order object from previous stage b). Spinup a new goroutine to process payment in a separate goroutine. c). Process payment perhaps via a separate payment gateway and marks order status as order.Paid=true or false d). publishes Payment done Order to an output channel (which will be sent to the next stage in the process).

prepareShipment : Its the fourth and final stage of the pipeline and performs: a). Takes in an input channel (passed from previous stage) to read Order object from previous stage b). Spinup a new goroutine to prepare for shipment in a separate goroutine. c). performs shipment and marks order status as order.Shipped=true or false d). publishes shipped Order to an output channel (which will be sent to the main function again to display the result).

main: main function mostly works as the orchestrator of the order processing. For now, it just dynamically generates five order objects and publishes on the `orders` channel which will be passed on to the first stage of the pipeline. Its handled in a separate goroutine so that it will happen on a separate goroutine without blocking main function flow.

In the next step it composes order processing pipeline stages.

Order pipeline is completely loosely coupled, should there be a need for another stage, it can be easily built and added at the pipeline without impacting any other stages or processing.

Each stage takes in a input channel from previous stage and creates an output channel and returns it only to pass on to next stage. That way whole pipeline is built.

Processes the result from the channel from final stage and displays the final order status to the user.

We use unbuffered channel throught the solution so that writing to and reading from the channel is not blocked improving more throughput while maintaining the order of `order` processing.

Sample output:


Subscribe to Alagesan Palani

Launched 5 months ago
Advanced Go (Golang), practical patterns, practices and solutions in software design and architecture, Microservices, Cloud, Kubernetes and DevOps.
Alagesan Palani's avatar
Chirag Bhatia's avatar
1 Like∙
1 Restack
1

Share this post

Alagesan Palani
Alagesan Palani
Five Go Concurrency Patterns, every Go Developer must know - Pipeline
Copy link
Facebook
Email
Notes
More
1
Share

Discussion about this post

User's avatar
Microservice Architecture
Independent, smaller services, enabling agility, scalability, and easier maintenance
Jan 19 â€¢ 
Alagesan Palani
1

Share this post

Alagesan Palani
Alagesan Palani
Microservice Architecture
Copy link
Facebook
Email
Notes
More
Dependency injection pattern in Go
with an easy implementation and unit/mock testing example
Dec 26, 2024 â€¢ 
Alagesan Palani

Share this post

Alagesan Palani
Alagesan Palani
Dependency injection pattern in Go
Copy link
Facebook
Email
Notes
More
Five Go Concurrency Patterns, every Go Developer must know - Worker Pool
Parallel processing of tasks with efficient system resource utilization
Dec 27, 2024 â€¢ 
Alagesan Palani

Share this post

Alagesan Palani
Alagesan Palani
Five Go Concurrency Patterns, every Go Developer must know - Worker Pool
Copy link
Facebook
Email
Notes
More

Ready for more?

© 2025 Alagesan Palani
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

Copy link
Facebook
Email
Notes
More

Create your profile

User's avatar

Only paid subscribers can comment on this post

Already a paid subscriber? Sign in

Check your email

For your security, we need to re-authenticate you.

Click the link we sent to , or click here to sign in.