Golang发出并发请求和合并响应

I have written go code to call multiple http request independently and combine the results.

Sometime values are missing on combined method.

func profile(req *http.Request)  (UserMe, error, UserRating, error) {

    wgcall := &sync.WaitGroup{}

    uChan := make(chan ResUser)
    rChan := make(chan ResRating)

        // variable inits
    var meResp UserMe
    var ratingResp UserRating

    go func() {
        res := <-uChan
                meResp = res.Value
    }()

    go func() {
        res := <-rChan
                ratingResp = res.Value
    }()

    wgcall.Add(2)
    go me(req, wgcall, uChan)
    go rate(req, wgcall, rChan)

    wgcall.Wait()

    logrus.Info(meResp)  // sometimes missing
    logrus.Info(ratingResp) // sometimes missing

    return meResp, meErr, ratingResp, ratingErr
}

But the me and rating calls returns the values from api requests as expected.

func me(req *http.Request, wg *sync.WaitGroup, ch chan ResUser) {
    defer wg.Done()

    // http call return value correclty
    me := ...
    ch <- ResUser{
        Value := // value from rest
    }
    logrus.Info(fmt.Sprintf("User calls  %v" , me))  // always return the values
    close(ch)
}

func rate(req *http.Request, wg *sync.WaitGroup, ch chan ResRating) {
    defer wg.Done()

        // make http call
    rating := ...
    ch <- ResRating{
        Value := // value from rest
    }
    logrus.Info(fmt.Sprintf("Ratings calls %v" , rating)) // always return the values

    close(ch)
}

Issue is: meResp and ratingResp on profile function not getting the values always. sometime only meResp or ratingResp, sometimes both as expected.

But me and rate function calls getting values always.

Can help me fix this plz ?

There's a race condition in your code.

There is no barrier to ensure the goroutines in the profile method which read from uChan and rChan have populated the variables meResp and ratingResp before you return from profile.

You can simplify your code immensely by dropping the use of channels and the inline declared goroutines in profile. Instead, simply populate the response values directly. There is no benefit provided by using channels or goroutines to read from them in this circumstance as you only intend to send one value and you have a requirement that the values produced by both HTTP calls are present before returning.

You might do this by modifying the signature of me and rate to receive a pointer to the location to write their output, or by wrapping their calls with a small function which receives their output value and populates the value in profile. Importantly, the WaitGroup should only be signalled after the value has been populated:

wgcall := &sync.WaitGroup{}

var meResp UserMe
var ratingResp RatingMe

wgcall.Add(2)
// The "me" and "rate" functions should be refactored to
// drop the wait group and channel arguments.
go func() {
    meResp = me(req)
    wgcall.Done()
}()
go func() {
    ratingResp = rate(req)
    wgcall.Done()
}()
wgcall.Wait()

// You are guaranteed that if "me" and "rate" returned valid values,
// they are populated in "meResp" and "ratingResp" at this point.

// Do whatever you need here, such as logging or returning.