Why is my function not waiting for the goroutines to complete?

Viewed 24

I have a function that makes a get request and then store both the response and the encoded response in a struct. It takes in a pointer to a wait group

Here is that function

type EncodedData string

type EncodedImage struct {
    Data        []byte
    EncodedData EncodedData
    Error       error
}

func GetPainting(url string, EI *EncodedImage, wg *sync.WaitGroup) {
    defer wg.Done()

    res, err := http.Get(url)
    if err != nil {
        EI.Error = errors.Wrapf(err, "unable to fetch from provided url %s", url)
    }

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        EI.Error = err
    }

    encoded := b64.StdEncoding.EncodeToString(body)
    EI.Data, EI.EncodedData = body, EncodedData(encoded)
}

Here is the function that calls the previous function. It's a handler for a gin router.

func Search(db *gorm.DB) gin.HandlerFunc {
    return func(c *gin.Context) {
        
        // this is just receiving a search term, making a query, and then loading it into "results". 
        term := c.Param("term")
        var results []models.Searches
        db.Table("searches").Where("to_tsvector(\"searches\".\"Title\" || '' || \"searches\".\"Artist_Name\") @@ plainto_tsquery(?)", term).Find(&results)

        
        var wg sync.WaitGroup

        // results is an slice of structs
        for i, re := range results {

            var ed EncodedImage
            wg.Add(1)

            // here is the function defined above
            go GetPainting(re.IMG, &ed, &wg)
            if ed.Error != nil {
                c.JSON(http.StatusInternalServerError, ed.Error.Error())
                panic(ed.Error)
            }

            results[i].IMG = fmt.Sprintf("data:image/jpeg;base64,%v", ed.EncodedData)
        }

        wg.Wait()
        c.JSON(http.StatusOK, results)
}

The JSON response shows "data:image/jpeg;base64," which means the goroutines aren't being waited on to completion

This all works without using additional goroutines. In other words, things stopped working when I introduced the go keyword. I wanted to try this to speed things up. Any insight or advice is greatly appreciated!

1 Answers
1. Try with mutex once it may work

type EncodedData string

type EncodedImage struct {
    Data        []byte
    EncodedData EncodedData
    Error       error
}

func GetPainting(url string, EI *EncodedImage, wg *sync.WaitGroup) {
    defer wg.Done()
    defer mutex.Unlock() // ensure that mutex unlocks

    // Lock the resource before accessing it
    mutex.Lock()

    res, err := http.Get(url)
    if err != nil {
        EI.Error = errors.Wrapf(err, "unable to fetch from provided url %s", url)
    }

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        EI.Error = err
    }

    encoded := b64.StdEncoding.EncodeToString(body)
    EI.Data, EI.EncodedData = body, EncodedData(encoded)
}
Related