Created
March 2, 2024 01:48
-
-
Save bamchoh/639c2c42d2422a2310b6bf50ee8cd2ef to your computer and use it in GitHub Desktop.
CTRL+Cを押してアプリを終了するときにwaitGroupでのWait()で無限待ちにならないようにする方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
単純に main関数の終わりで シグナルを待つようにすれば無限待ちにならない | |
以前は main関数の終わりでは wg.Wait()で待つようにしていて | |
シグナルを待つ処理をゴルーチンでやってシグナルが来たらcancel()を読んで | |
ほかのゴルーチンに通知する方式でやっていた。 | |
この方式だと、いろんなところに ctx.Done() とのselect を書く必要があり | |
書き忘れが発生するとタスクをキルするしかなくなっていた | |
今回の方法だと書き忘れがあってもアプリがちゃんと終了してくれるので | |
コードもすっきりするし期待した動作もしてくれるしで両方ハッピー | |
*/ | |
package main | |
import ( | |
"context" | |
"fmt" | |
"math/rand" | |
"os" | |
"os/signal" | |
"sync" | |
"syscall" | |
"time" | |
) | |
func fn(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup, name string, n int) { | |
defer wg.Done() | |
rnd := rand.Intn((n + 1) * 100) | |
for { | |
select { | |
case <-ctx.Done(): | |
fmt.Printf("%s(%d) : another func timedout\n", name, n) | |
return | |
case <-time.After(time.Duration(rnd) * time.Millisecond): | |
fmt.Printf("%s(%d) : timeout after %d ms\n", name, n, rnd) | |
cancel() | |
return | |
} | |
} | |
} | |
func loop(i int) { | |
var wg sync.WaitGroup | |
ctx, cancel := context.WithCancel(context.Background()) | |
wg.Add(1) | |
go fn(ctx, cancel, &wg, "func1", i) | |
wg.Add(1) | |
go fn(ctx, cancel, &wg, "func2", i) | |
wg.Wait() | |
} | |
func main() { | |
sigs := make(chan os.Signal, 1) | |
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) | |
go func() { | |
for i := 0; ; i++ { | |
loop(i) // 複雑な並行処理 | |
time.Sleep(1 * time.Second) | |
} | |
}() | |
fmt.Println("awaiting signal") | |
<-sigs | |
fmt.Println("exiting") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment