Ensuring goroutine cleanup, bestpractice
<p>I have a fundamental understanding problem about how to make sure that spawned goroutines are "closed" properly in the context of long-running processes. I watched talks regarding that topic and read about best practices. In order to understand my question please refer to the video "Advanced Go Concurrency Patterns" <a href="https://www.youtube.com/watch?v=QDDwwePbDtw" rel="nofollow">here</a></p>

<p>For the following, if you run code on your machine please export the environment variable <code>GOTRACEBACK=all</code> so you are able to see routine states after panic.</p>

<p>I put the code for the original example here: <a href="https://play.golang.org/p/mO3ieM6U8l" rel="nofollow">naive</a> (it does not execute on go playground, I guess bacause a time statement is used. Please copy the code and execute it locally)</p>

<p>The result of the panic of the naive implementation after execution is </p>

<p><code>
    panic: show me the stacks
    goroutine 1 [running]:
    panic(0x48a680, 0xc4201d8480)
        /usr/lib/go/src/runtime/panic.go:500 +0x1a1
    main.main()
        /home/flx/workspace/go/go-rps/playground/ball-naive.go:18 +0x16b
    goroutine 5 [chan receive]:
    main.player(0x4a4ec4, 0x2, 0xc42006a060)
        /home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
    created by main.main
        /home/flx/workspace/go/go-rps/playground/ball-naive.go:13 +0x76
    goroutine 6 [chan receive]:
    main.player(0x4a4ec6, 0x2, 0xc42006a060)
        /home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
    created by main.main
        /home/flx/workspace/go/go-rps/playground/ball-naive.go:14 +0xad
    exit status 2</code></p>

<p>That demonstrates the underlying problem of leaving dangling goroutines on the system, which is especially bad for long running processes.</p>

<p>So for my personal understanding I tried two slightly more sophisticated variants to be found here:</p>

<p><a href="https://play.golang.org/p/QsIvUp1c2g" rel="nofollow">for-select with default</a></p>

<p><a href="https://play.golang.org/p/71EptxbQ8z" rel="nofollow">generator pattern with quit channel</a></p>

<p>(again, not executable on the playground, cause "process takes too long")</p>

<p>The first solution is not fitting for various reasons, even leading to non-determinism in executed steps, depending on goroutine execution speed.</p>

<p>Now I thought -- and here finally comes the question! -- that the second solution with the quit channel would be appropriate to eliminate all executional traces from the system before exiting. Anyhow, "sometimes" the program exits too fast and the panic reports an additional goroutine runnable still residing on the system. The panic output:</p>

<p><code>panic: show me the stacks
    goroutine 1 [running]:
    panic(0x48d8e0, 0xc4201e27c0)
        /usr/lib/go/src/runtime/panic.go:500 +0x1a1
    main.main()
        /home/flx/workspace/go/go-rps/playground/ball-perfect.go:20 +0x1a9
    goroutine 20 [runnable]:
    main.player.func1(0xc420070060, 0x4a8986, 0x2, 0xc420070120)
        /home/flx/workspace/go/go-rps/playground/ball-perfect.go:27 +0x211
    created by main.player
        /home/flx/workspace/go/go-rps/playground/ball-perfect.go:36 +0x7f
    exit status 2</code></p>

<p>My question is: that should not happen, right? I do use a quit channel to cleanup state before stepping forward to panicking.</p>

<p>I did a final try of implementing safe cleanup behavior here:
<a href="https://play.golang.org/p/RgxphCTXUD" rel="nofollow">artificial wait time for runnables to close</a></p>

<p>Anyhow, that solution does not feel right and may as well not be applicable to large amounts of runnables?</p>

<p>What would be the recommended and most idiomatic pattern to ensure correct cleanup?</p>

<p>Thanks for your time</p>