Skip to content

Instantly share code, notes, and snippets.

@innermond
Created December 5, 2018 14:50
Show Gist options
  • Save innermond/02e0bc1b041ec7e6a2ad649a9e875c60 to your computer and use it in GitHub Desktop.
Save innermond/02e0bc1b041ec7e6a2ad649a9e875c60 to your computer and use it in GitHub Desktop.
example how to cancel, timeout, ctrl + c with cleaning after an operation that lasts
package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"strconv"
"time"
)
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
defer func() {
signal.Stop(c)
cancel()
}()
go func() {
<-c
fmt.Println("stop")
cancel()
}()
longRunningOperation(ctx)
}
func longRunningOperation(ctx context.Context) {
f, err := os.Create("test")
if err != nil {
log.Fatal(err)
}
defer f.Close()
var i int
var undo bool
work:
for {
select {
// cancelable branch
case <-ctx.Done():
fmt.Println("canceled")
undo = true
break work
// timeout branch
case <-time.After(3 * time.Second):
fmt.Println("timeout")
undo = true
break work
// working branch
default:
fmt.Println("working", i)
time.Sleep(100 * time.Millisecond)
_, err := f.WriteString(strconv.Itoa(i) + "\n")
// on error clear working's result
if err != nil {
undo = true
break work
}
// finally work done flawlessly
if i > 100{
undo = false
break work
}
i++
}
}
if undo {
fmt.Println("longRunningOperation result will be cleared")
f.Truncate(int64(0))
return
}
fmt.Println("longRunningOperation finished")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment