-
Notifications
You must be signed in to change notification settings - Fork 42
Open
Labels
Description
Repro steps:
// With [EDQueue sharedInstance] stopped
[[EDQueue sharedInstance] enqueueWithData:@{"test" : "data"} forTask:@"task"];
[[EDQueue sharedInstance] enqueueWithData:@{"test" : "data"} forTask:@"task2"];
[[EDQueue sharedInstance] start];
Expected:
The queue should ask its delegate to execute "task", wait for that to be completed, then follow by asking its delegate to complete "task2".
Actual:
A race condition occurs which can cause the queue to ask its delegate to process "task" and/or "task2" multiple times.
Bug description:
Here's my understanding of why this is happening:
enqueueWithData:callstickafter inserting the job into the storage engine.startalso callstickafter settingisRunningto true.tickdispatches a block to a background queue that asks its delegate to execute that job.isRunningis checked inside that async call to determine whether the delegate actually gets asked to complete the job.- Calling
enqueueWithData:before callingstartdispatches multiple async blocks that all can ask the delegate to process at the first job in the queue. The blocks that are executed afterisRunningis set to true will all ask their delegate to process the first job in the queue (i.e. it duplicates calls for the same job). This causes duplicate calls to the delegate for the same job.
It seems like the solution is to wrap the tick call in enqueueWithData, but would love feedback on whether that would break use-cases I haven't thought about.
Here's a modified enqueueWithData:
if (data == nil) data = @{};
[self.engine createJob:data forTask:task];
if (self.isRunning)
[self tick];