DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
HardMachine Coding

Implement errgroup from Scratch

39 views

Problem Statement

At Uber, we need to fetch data from multiple microservices concurrently. If any service fails, we should cancel all other requests and return the first error. Implement the errgroup package functionality from scratch.

Requirements

  • Run multiple goroutines concurrently
  • If any goroutine returns an error, cancel all others
  • Wait for all goroutines to complete
  • Return the first error encountered

Implementation

package errgroup

import (
    "context"
    "sync"
)

type Group struct {
    cancel  context.CancelFunc
    wg      sync.WaitGroup
    errOnce sync.Once
    err     error
}

func WithContext(ctx context.Context) (*Group, context.Context) {
    ctx, cancel := context.WithCancel(ctx)
    return &Group{cancel: cancel}, ctx
}

func (g *Group) Go(f func() error) {
    g.wg.Add(1)
    go func() {
        defer g.wg.Done()
        
        if err := f(); err != nil {
            g.errOnce.Do(func() {
                g.err = err
                if g.cancel != nil {
                    g.cancel()
                }
            })
        }
    }()
}

func (g *Group) Wait() error {
    g.wg.Wait()
    if g.cancel != nil {
        g.cancel()
    }
    return g.err
}

Usage Example

package main

import (
    "context"
    "fmt"
    "net/http"
)

func main() {
    g, ctx := errgroup.WithContext(context.Background())
    
    urls := []string{
        "https://api.service-a.com/data",
        "https://api.service-b.com/data",
        "https://api.service-c.com/data",
    }
    
    results := make([]string, len(urls))
    
    for i, url := range urls {
        i, url := i, url // Capture loop variables
        g.Go(func() error {
            req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
            resp, err := http.DefaultClient.Do(req)
            if err != nil {
                return err
            }
            defer resp.Body.Close()
            // Process response...
            results[i] = "success"
            return nil
        })
    }
    
    if err := g.Wait(); err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Println("All requests succeeded")
}

Edge Cases to Handle

  • Multiple goroutines returning errors simultaneously
  • Panic in a goroutine (add recover)
  • Context already cancelled before Go() is called

Follow-up Questions

  1. How would you add a limit to concurrent goroutines?
  2. How would you collect all errors instead of just the first?
  3. How does the real golang.org/x/sync/errgroup handle panics?

Sample Test Cases

Case 1
Input
goroutines=[success, success, success]
Expected Output
Wait() returns nil
Case 2
Input
goroutines=[success, error, success]
Expected Output
Wait() returns first error
Case 3
Input
[]
Expected Output
null
Case 4
Input
[]
Expected Output
null
Case 5
Input
[{"delay": 100, "error": false}, {"delay": 200, "error": false}, {"delay": 50, "error": false}]
Expected Output
null
Case 6
Input
[{"delay": 100, "error": false}, {"delay": 200, "error": false}]
Expected Output
null
Case 7
Input
[{"delay": 100, "error": false}, {"delay": 200, "error": true, "errorMessage": "Service B failed"}, {"delay": 50, "error": false}]
Expected Output
"Service B failed"
Case 8
Input
[{"delay": 100, "error": true, "errorMessage": "Task failed"}, {"delay": 200, "error": false}]
Expected Output
"Task failed"

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
39
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go