-
Notifications
You must be signed in to change notification settings - Fork 3
Calling init on worker pool twice no longer blocks #144
base: master
Are you sure you want to change the base?
Conversation
sync/worker_pool.go
Outdated
@@ -56,6 +56,9 @@ func NewWorkerPool(size int) WorkerPool { | |||
} | |||
|
|||
func (p *workerPool) Init() { | |||
if len(p.workCh) == cap(p.workCh) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the length of the worker channel can change as the pool is used would it be better to instead use an internal flag and only initialize the channel if the flag is not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The work channel is not public, so it would have to change within this package, and there is no code to do that right now.
But in the future, I suppose it could change if some functionality was added. I can use a flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just meant that if one calls Go
on the worker pool that will decrement the length of the channel until the worker is put back on the queue. So if there are any concurrent calls to Go
between calls to Init
you'll run into the same issue.
sync/worker_pool_test.go
Outdated
@@ -121,3 +121,23 @@ func TestGoWithTimeout(t *testing.T) { | |||
|
|||
require.Equal(t, uint32(testWorkerPoolSize+1), count) | |||
} | |||
|
|||
func TestFullWorkerPool(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not exactly sure what is this testing, if you remove the second Init() does the test still pass? Also should probably rename this test to something like TestInitOnInitializedWorkerPool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah this test is a little odd because init does not return anything. I just wanted to show that this no longer hangs forever. Maybe the name change will make it clear.
Is this really necessary by the way? I think in most cases the expectation is that |
Either that or we can just get rid of the init method altogether, it'll be more expensive to create the worker pool when using the constructor but everyone usually just calls Init straight afterwards anyhow. |
sync/worker_pool_test.go
Outdated
@@ -121,3 +121,23 @@ func TestGoWithTimeout(t *testing.T) { | |||
|
|||
require.Equal(t, uint32(testWorkerPoolSize+1), count) | |||
} | |||
|
|||
func TestInitOnInitializedWorkerPool(t *testing.T) { | |||
var count uint32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels a better test would be:
p := NewWorkerPool(testWorkerPoolSize)
p.Init()
var wg sync.WaitGroup
wg.Add(1)
go func() {
p.Init()
wg.Done()
}
wg.Wait()
This way it's clear that it's avoiding the hanging, rather than checking the counts and stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I was thinking there should be some assert in the test but I suppose that is not necessarily true.
@xichen2020 totally valid that we just use documentation to handle this issue. As you can see in the description this only came up from a fat finger and it struck me as kind of odd. I think either documentation, error, or noops are all valid solutions, as long as we have a consistent design principle, but currently, we don't have any one of those solutions so we should pick one. Personally, I would prefer errors or noops over documentation but I think consistency is most important. @robskillington yep. I was trying to avoid a backwards breaking change, but you are right that does seem like the common pattern. |
Codecov Report
@@ Coverage Diff @@
## master #144 +/- ##
==========================================
+ Coverage 77.1% 77.21% +0.11%
==========================================
Files 79 79
Lines 3188 3191 +3
==========================================
+ Hits 2458 2464 +6
+ Misses 664 661 -3
Partials 66 66 Continue to review full report at Codecov.
|
While working on a service that used two worker pool I accidentally fat fingered and called init twice on the same worker pool. As a result, the service hung forever because we try to blindly push to an already full channel.
This diff checks to see if there are already workers in the channel and if there are just returns. I could see this going either way where we panic/error or silently return. If someone feels strongly about one way or the other I would happy to make a change.