Nakeuh
Nakeuh

Reputation: 1909

How to start and stop a function

I have a go function processing that use two distinct goroutines. produce will push some data into a channel and consume will read these data. Here is an example:

type MyObject struct{
    ...
}

func processing() {
    var wg sync.WaitGroup
    dataChannel := make(chan MyObject, 5)

    wg.Add(2)

    go produce(wg, dataChannel)
    go consume(wg, dataChannel)

    wg.Wait()
}

func produce (wg *sync.WaitGroup, dataChannel chan MyObject){
    for{
        // Produce data in dataChannel
    }
}

func consume (wg *sync.WaitGroup, dataChannel chan MyObject){
    for{
        // Consume data from dataChannel
    }
}

I want my processing function to be started and stoped by an HTTP call. So I am looking to do something as follow:

func main() {

    // echo instance
    e := echo.New()
    e.GET("/", startProcessing)
    e.Logger.Fatal(e.Start(":8099"))
}

func startProcessing(c echo.Context) error{

    command := c.QueryParam("command")

    if(command == "start"){
        processing()
    }else if(command == "stop"){
        if (/* ? processing is running ? */){
            /* ? stop processing process? */
        }
    }       
}

What is the correct way to do this with Go?

Upvotes: 1

Views: 73

Answers (1)

wasmup
wasmup

Reputation: 16213

Here how to start and stop a function using context, try this:

package main

import (
    "context"
    "fmt"
    "sync"
    "time"
)

func main() {
    ctx, cancel := context.WithCancel(context.Background())
    var wg sync.WaitGroup
    dataChannel := make(chan MyObject, 5)
    wg.Add(2)
    go produce(ctx, &wg, dataChannel)
    go consume(&wg, dataChannel)

    time.Sleep(1 * time.Second)
    cancel() // cancel when we are finished consuming data

    wg.Wait()
}

func produce(ctx context.Context, wg *sync.WaitGroup, dataChannel chan MyObject) {
    defer wg.Done()
    i := 1
    for {
        select {
        case <-ctx.Done():
            close(dataChannel)
            return // returning not to leak the goroutine
        case dataChannel <- MyObject{i}:
            i++
            time.Sleep(250 * time.Millisecond)
        }
    }
}

func consume(wg *sync.WaitGroup, dataChannel chan MyObject) {
    defer wg.Done()
    for v := range dataChannel {
        fmt.Println(v)
    }
}

type MyObject struct {
    i int
}


For HTTP you need to do it yourself!
It needs to have some concurrent safe ID or map or something to keep track of how many functions you called and then call a cancel() to stop it.

Upvotes: 3

Related Questions