Search code examples
gochannelsubroutine

How to allow multiple objects get data from a single go subroutine


I have a case where I want to spin up a go subroutine that will fetch some data from a source periodically. If the call fails, it stores the error until the next call succeeds. Now there are several instances in the code where a instance would access this data pulled by the go subroutine. How can I implement something like that?

UPDATE

I have had some sleep and coffee in me and I think I need to rephrase the problem more coherently using java-ish semantics.

I have come up with a basic singleton pattern that returns me a interface implementation that is running a go subroutine internally in a forever loop (lets put the cardinal sin of forever loops aside for a moment). The problem is that this interface implementation is being accessed by multiple threads to get the data collected by the go subroutine. Essentially, the data is pulled every 10 mins by the subroutine and then requested infinite number of times. How can I implement something like that?


Solution

  • Here's a very basic example of how you can periodically fetch and collect data.

    Have in mind: running this code will do nothing as main will return before anything really happens, but how you handle this depends on your specific use case. This code is really bare bones and needs improvements. It is a sketch of a possible solution to a part of your problem :)

    I didn't handle errors here, but you could handle them the same way fetched data is handled (so, one more chan for errors and one more goroutine to read from it).

    func main() {
    
        period := time.Second
        respChan := make(chan string)
        cancelChan := make(chan struct{})
        dataCollection := []string
    
        // periodicaly fetch data and send it to respChan
        go func(period time.Duration, respChan chan string, cancelChan chan struct{}) {
            ticker := time.Ticker(period)
            for {
                select {
                case <-ticker.C:
                    go fetchData(respChan)
                case <-cancelChan:
                    // close respChan to stop reading goroutine
                    close(respChan)
                    return
                }
            }
        }(period, cancelChan)
    
        // read from respChan and write to dataCollection
        go func(respChan chan string) {
            for data := range respChan {
                dataCollection = append(dataCollection, data)
            }
        }(respChan)
    
        // close cancelChan to gracefuly stop the app
        // close(cancelChan)
    }
    
    
    func fetchData(respChan chan string) {
        data := "fetched data"
        respChan <- data
    }