A buffered channel lets a producer send values without waiting for each value to be received. Its capacity sets how many values can be queued; once the buffer is full, another send blocks until a receiver takes a value. In Go, `make(chan *gofeed.Article, 10)` creates a channel with room for ten article pointers. section 9.4
func (a *App) fetchFeed(ctx context.Context, url string) {
...
fmt.Println("fetched: ", url)
out := make(chan *gofeed.Article, 10) #1
go a.saveFeed(out)
...
}
The article-ingestion channel uses a capacity of ten so fetching can continue while a separate goroutine saves articles. section 9.4
The same pattern works at the application boundary. An application can queue feed URLs in a buffered channel, then have a background goroutine receive them. A worker pool extends this design: workers share one buffered URL channel and take queued work as they become available. Buffer capacity controls how much work can wait; the number of workers controls how many workers receive from that queue. section 9.4 section 9.5.1
Listing 9.21 main.go: Worker pools
type WorkerPool struct {
workers []*Worker #1
incomingFeeds chan string #2
}
func NewWorkerPool(app *App, count int) *WorkerPool {
wp := &WorkerPool{}
wp.incomingFeeds := make(chan string, 100) #3
for i := range count {
w := NewWorker(app, incomingFeeds) #4
append(wp.workers, w)
}
return wp
}
func (wp *WorkerPool) Submit(url string) {
wp.incomingFeeds <- url #5
}
func (wp *WorkerPool) Stop() {
close(wp.incomingFeeds)
}
The worker-pool listing illustrates a shared URL channel with capacity 100, a submission method that sends to it, and workers that receive from it. section 9.5.1


