This program runs a function LongRunningTask in a go routine called from main. It creates or opens a file, then waits for 5 seconds, writes to the file and then the deferred function in the end closes the file and writes to the channel.
main listens on this channel and once it gets a message it then exits the application.
Now if run this program and don't interrupt by pressing ctrl+c on the keyboard it gives the output as follows which is right - but it does not run the deferred function in the end here which is responsible for closing the file and printing a message.
successfully written to file..
writing to channel
Exiting application
And if I run the same program and press ctrl+c within 5 seconds, it receives a shutdown signal as expected and then runs the deferred function, writes a message to the channel and exits. The output it as follows
^CReceived a shutdown signal
long running task cancelled.. exiting now..
writing to channel
file closed successfully..
Exiting application
Program code
package main
import (
"context"
"fmt"
"os"
"os/signal"
"time"
)
func LongRunningTask(ctx context.Context, c chan bool) {
file, err := os.OpenFile("data.txt", os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
fmt.Println("error opening the file - ", err)
return
}
defer func() {
if err := file.Close(); err != nil {
fmt.Println("error closing the file - ", err)
} else {
fmt.Println("file closed successfully..")
}
}()
select {
case <-ctx.Done():
fmt.Println("long running task cancelled.. exiting now..")
case <-time.After(time.Second * 5):
message := []byte("sample data")
_, err = file.Write(message)
if err != nil {
fmt.Println("error writing to the file")
}
fmt.Println("successfully written to file..")
}
fmt.Println("writing to channel")
c <- true
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
s := make(chan os.Signal, 1)
signal.Notify(s, os.Interrupt)
go func() {
<-s
fmt.Println("Received a shutdown signal")
cancel()
}()
c := make(chan bool)
go LongRunningTask(ctx, c)
<-c
fmt.Println("Exiting application")
}
If i move c <- true inside the deferred function, then the deferred function gets called irrespective of the first or 2nd case in select but otherwise the deferred function is only called in the first case of select
I understood that when I move the channel writing logic inside the deferred function, it will always work for both the select cases as main is blocking on that channel but what I don't understand is if the writing to channel logic is outside of the deferred function where it's originally in the sample code above, then why is the deferred function only called when the first case inside select is matched and not the on second one?