liveBook · Manning

Fan-out/fan-in pattern

As explained in Go in Action, Second Edition

Fan-out/fan-in is a concurrency pattern that distributes work across concurrent executions and then combines their results.

Fan-out/fan-in distributes independent work across concurrent goroutines, then gathers the results into one controlled response. Fan-out launches parallel operations; fan-in collects their outputs, combines successful data, and handles errors without waiting for one operation to finish before starting another. section 9.5

A Go implementation typically follows this sequence:

  • Create a results channel whose messages contain both successful data and errors. section 9.5.2
  • Launch one goroutine per independent task and pass each goroutine its own input. section 9.5.2
  • Use a WaitGroup to track completion, then close the results channel after every goroutine finishes. section 9.5.2
  • Range over the channel as results arrive, aggregating data and recording errors regardless of completion order. section 9.5.2

Synchronizing multiple news feeds

A /sync HTTP handler fans out by starting a goroutine for each RSS feed URL. Each operation fetches and saves articles with a request timeout, then sends articles and any error through a shared results channel. The handler fans in by collecting all results, returning aggregated articles when successful or a partial-content response containing both articles and errors. section 9.5.2

Listing 9.23 main.go: New handler for fan-out/fan-in call
func (a *App) syncHandler(w http.ResponseWriter, r *http.Request) {

 // Fan-out: launch goroutines for each feed
 type result struct {
    articles []*gofeed.Item
    err      error
 }
 resultsChan := make(chan result, len(feeds)) #1
 var wg sync.WaitGroup #2

 for _, feedURL := range feeds {
    wg.Add(1)
    go func(url string) {
     defer wg.Done()
     ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
     defer cancel()

     fetchedArticles, err := a.fetchFeed(ctx, url)
     resultsChan <- result{articles: fetchedArticles, err: err} #3
    }(feedURL)
 }

 // Close results channel after all goroutines complete
 go func() {
    wg.Wait()
    close(resultsChan)
 }() #4

Inspect the handler structure for launching goroutines, applying timeouts, publishing results, and coordinating channel closure. section 9.5.2

How Go in Action, Second Edition covers it

How deep it goes
Implements goroutine launch, result channels, WaitGroup coordination, channel closure, aggregation, and error handling.
Examples
Demonstrates parallel RSS fetching, article saving, result aggregation, timeouts, and partial responses from an HTTP endpoint.
What it assumes
Assumes familiarity with Go concurrency basics while reinforcing goroutines, channels, synchronization, timeouts, and explicit error handling.
What you can do after
Build concurrent Go handlers that fetch independent sources in parallel and return combined results with explicit errors.
How it connects
Connects goroutines, channels, WaitGroup, context.Context, error handling, and worker pools.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Action, Second Edition. The section links point to the parts of the book it draws on.