Skip to content

Commit 2dc1126

Browse files
committed
Corrects EventLoopScheduler issue. Fixes #184
1 parent cc84689 commit 2dc1126

File tree

2 files changed

+44
-18
lines changed

2 files changed

+44
-18
lines changed

src/Scheduler/EventLoopScheduler.php

+21-14
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,27 @@ function ($ms, $callable) use ($timerCallableOrLoop) {
4242
});
4343
}
4444

45+
private function scheduleStartup()
46+
{
47+
if ($this->insideInvoke) {
48+
return;
49+
}
50+
$this->currentTimer->dispose();
51+
$this->nextTimer = $this->getClock();
52+
$this->currentTimer = call_user_func($this->delayCallback, 0, [$this, 'start']);
53+
}
54+
4555
public function scheduleAbsoluteWithState($state, int $dueTime, callable $action): DisposableInterface
4656
{
47-
$disp = parent::scheduleAbsoluteWithState($state, $dueTime, $action);
57+
$disp = new CompositeDisposable([
58+
parent::scheduleAbsoluteWithState($state, $dueTime, $action),
59+
new CallbackDisposable(function () use ($dueTime) {
60+
if ($dueTime > $this->nextTimer) {
61+
return;
62+
}
63+
$this->scheduleStartup();
64+
})
65+
]);
4866

4967
if ($this->insideInvoke) {
5068
return $disp;
@@ -54,20 +72,9 @@ public function scheduleAbsoluteWithState($state, int $dueTime, callable $action
5472
return $disp;
5573
}
5674

57-
$this->nextTimer = $this->getClock();
58-
59-
$this->currentTimer->dispose();
60-
$this->currentTimer = call_user_func($this->delayCallback, 0, [$this, 'start']);
75+
$this->scheduleStartup();
6176

62-
return new CompositeDisposable([
63-
$disp,
64-
new CallbackDisposable(function () {
65-
if (!$this->insideInvoke) {
66-
$this->currentTimer->dispose();
67-
$this->currentTimer = call_user_func($this->delayCallback, 0, [$this, 'start']);
68-
}
69-
})
70-
]);
77+
return $disp;
7178
}
7279

7380
public function start()

test/Rx/Scheduler/EventLoopSchedulerTest.php

+23-4
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public function testScheduledItemsFromOutsideOfSchedulerDontCreateExtraTimers()
167167
$this->assertEquals($timersExecuted, 3);
168168
}
169169

170-
public function testMultipleSchedulersFromOutsideInSameTickDontCreateExtraTimers()
170+
public function testMultipleSchedulesFromOutsideInSameTickDontCreateExtraTimers()
171171
{
172172
$timersCreated = 0;
173173
$timersExecuted = 0;
@@ -190,13 +190,13 @@ public function testMultipleSchedulersFromOutsideInSameTickDontCreateExtraTimers
190190
$scheduler->schedule(function () {}, 25)->dispose();
191191
$scheduler->schedule(function () {}, 24)->dispose();
192192
$scheduler->schedule(function () {}, 23)->dispose();
193-
$scheduler->schedule(function () {}, 22)->dispose();
193+
$scheduler->schedule(function () {}, 25)->dispose();
194194
});
195195

196196
$loop->run();
197197

198-
$this->assertEquals($timersCreated, 3);
199-
$this->assertEquals($timersExecuted, 3);
198+
$this->assertEquals(3, $timersCreated);
199+
$this->assertEquals(3, $timersExecuted);
200200
}
201201

202202
public function testThatStuffScheduledWayInTheFutureDoesntKeepTheLoopRunningIfDisposed()
@@ -244,4 +244,23 @@ public function testThatDisposalOfSingleScheduledItemOutsideOfInvokeCancelsTimer
244244

245245
$this->assertLessThan(2, $endTime - $startTime);
246246
}
247+
248+
public function testScheduledItemPastNextScheduledItemKillsItOwnTimerIfItBecomesTheNextOneAndIsDisposed()
249+
{
250+
$loop = Factory::create();
251+
$scheduler = new EventLoopScheduler($loop);
252+
253+
$startTime = microtime(true);
254+
255+
$scheduler->schedule(function () {}, 30);
256+
$disp = $scheduler->schedule(function () {}, 3000);
257+
$loop->addTimer(0.050, function () use ($disp) {
258+
$disp->dispose();
259+
});
260+
261+
$loop->run();
262+
$endTime = microtime(true);
263+
264+
$this->assertLessThan(2, $endTime - $startTime);
265+
}
247266
}

0 commit comments

Comments
 (0)