Is it possible to stop a ticker/goroutine from an outside function?

Issue

So, I have this (just an example):

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(5 * time.Second)
    for {
        select {
        case <-ticker.C:
            fmt.Println("hello")
        }
    }
}

This is an infinite loop, and I want it that way. In the real code it loops every 1 hour.
But, what if I want to call a func to make it stop looping? Is this possible?
Something like:

func stop() {
//this will stop the main function from looping
}

I know I could do something like:

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(5 * time.Second)
    done := make(chan bool)
    go func() {
        for {
            select {
            case <-done:
                fmt.Println("done")
                ticker.Stop()
                return
            case <-ticker.C:
                fmt.Println("hello")
            }
        }
    }()

    time.Sleep(10 * time.Second)
    done <- true
}

But that would be stoping the function from a predefined time frame(in this case 10 seconds), which is not what I want and also this is all within the same function, I need to make a call from outside the main function.

Is this possible somehow?

Solution

Here:

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func stop(ch chan<- struct{}) {
    select {
    // Triggers after 7 seconds
    case <-time.After(7 * time.Second):
        ch <- struct{}{}
    }
}

func signalStop(ch chan<- struct{}) {
    // Use a buffered channel (size = 1)
    sig := make(chan os.Signal, 1)
    // Use SIGINT signal i.e.,  <kill -SIGINT XXXX> or <Control+C>
    signal.Notify(sig, syscall.SIGINT)
    select {
    // Capture the SIGINT signal
    case <-sig:
        // Close the channel
        close(ch)
    }
}

func main() {
    ticker := time.NewTicker(1 * time.Second)
    done := make(chan struct{})
    // Spawn a goroutine with the done channel
    go signalStop(done)
    for {
        select {
        case <-ticker.C:
            fmt.Println("Hello!")
        case <-done:
            // When stop signals, stop the ticker and return
            ticker.Stop()
            fmt.Println("Bye, bye!")
            return
        }
    }
}

I’ve commented the relevant parts of the code so that you understand what I’m trying to do.

Answered By – shmsr

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.