alitto / pond

🔘 Minimalistic and High-performance goroutine worker pool written in Go
MIT License
1.43k stars 60 forks source link

Deadlock occurs when the pool parent context is canceled with queued tasks in the worker. #61

Closed CorentinClabaut closed 2 months ago

CorentinClabaut commented 2 months ago

The following test will block forever:

func TestSubmitWithContextCancelWithIdleTasks(t *testing.T) {

    ctx, cancel := context.WithCancel(context.Background())

    pool := pond.New(1, 5, pond.Context(ctx))

    var doneCount, taskCount int32

    // Submit a long-running, cancellable task
    pool.Submit(func() {
        atomic.AddInt32(&taskCount, 1)
        select {
        case <-ctx.Done():
            return
        case <-time.After(1 * time.Minute):
            atomic.AddInt32(&doneCount, 1)
            return
        }
    })

    // Submit a long-running, cancellable task
    pool.Submit(func() {
        atomic.AddInt32(&taskCount, 1)
        select {
        case <-ctx.Done():
            return
        case <-time.After(1 * time.Minute):
            atomic.AddInt32(&doneCount, 1)
            return
        }
    })

    // Cancel the context
    cancel()

    pool.StopAndWait()

    assertEqual(t, int32(1), atomic.LoadInt32(&taskCount))
    assertEqual(t, int32(0), atomic.LoadInt32(&doneCount))
}