> I want to be able to terminate each worker independently of others
> (i.e. close on worker, wait for it to finish its tasks, but allow
> other workers to run if they haven't been signalled to stop).

The solution I use is to have each worker take two parameters:

  - a channel that will be closed by the main program in order to signal
    that the worker should terminate;
  - a channel that will be closd by the worker when it's done.

So the worker looks like this:

    func worker(terminate chan struct{}, done chan struct{}) {
        defer close(done)
      outer:
        for {
            work();
            select {
                case <-done: break outer
                default:
            }
        }
    }

and the main program looks like this:

    terminate := make(chan struct{})
    done := make(chan struct{})
    go worker(terminate, done)
    ...
    close(terminate)
    <-done

The terminate channel can be replaced by a context, which is useful if
you have a tree of workers to manage:

    terminate, terminateFn := context.WithCancel(context.Background())
    done := make(chan struct{})
    go worker(terminate, done)
    ...
    terminateFn()
    <-done

Or perhaps with a timeout in case a worker gets stuck:

    terminate, terminateFn := context.WithCancel(context.Background())
    done := make(chan struct{})
    go worker(terminate, done)
    ...
    terminateFn()
    timeout := time.NewTimer(5 * time.Second)
    select {
       case <-done:
           timeout.Cancel()
       case <-timeout.C:
           log.Println("Worker failed to terminate within 5s")
   }

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/87y28jnobp.fsf%40pirx.irif.fr.

Reply via email to