|
3 | 3 | namespace Clue\React\Mq; |
4 | 4 |
|
5 | 5 | use React\Promise; |
| 6 | +use React\Promise\CancellablePromiseInterface; |
6 | 7 | use React\Promise\Deferred; |
7 | 8 | use React\Promise\PromiseInterface; |
8 | 9 |
|
@@ -134,30 +135,26 @@ public function __invoke() |
134 | 135 | end($queue); |
135 | 136 | $id = key($queue); |
136 | 137 |
|
137 | | - $deferred = new Deferred(function ($_, $reject) use (&$queue, $id) { |
138 | | - // queued promise cancelled before its handler is invoked |
139 | | - // remove from queue and reject explicitly |
140 | | - unset($queue[$id]); |
141 | | - $reject(new \RuntimeException('Cancelled queued job before processing started')); |
| 138 | + $deferred = new Deferred(function ($_, $reject) use (&$queue, $id, &$deferred) { |
| 139 | + // forward cancellation to pending operation if it is currently executing |
| 140 | + if (isset($deferred->pending) && $deferred->pending instanceof CancellablePromiseInterface) { |
| 141 | + $deferred->pending->cancel(); |
| 142 | + } |
| 143 | + unset($deferred->pending); |
| 144 | + |
| 145 | + if (isset($deferred->args)) { |
| 146 | + // queued promise cancelled before its handler is invoked |
| 147 | + // remove from queue and reject explicitly |
| 148 | + unset($queue[$id], $deferred->args); |
| 149 | + $reject(new \RuntimeException('Cancelled queued job before processing started')); |
| 150 | + } |
142 | 151 | }); |
143 | 152 |
|
144 | 153 | // queue job to process if number of pending jobs is below concurrency limit again |
| 154 | + $deferred->args = func_get_args(); |
145 | 155 | $queue[$id] = $deferred; |
146 | 156 |
|
147 | | - // once number of pending jobs is below concurrency limit again: |
148 | | - // await this situation, invoke handler and await its resolution before invoking next queued job |
149 | | - $handler = $this->handler; |
150 | | - $args = func_get_args(); |
151 | | - $that = $this; |
152 | | - $pending =& $this->pending; |
153 | | - return $deferred->promise()->then(function () use ($handler, $args, $that, &$pending) { |
154 | | - ++$pending; |
155 | | - |
156 | | - // invoke handler and await its resolution before invoking next queued job |
157 | | - return $that->await( |
158 | | - call_user_func_array($handler, $args) |
159 | | - ); |
160 | | - }); |
| 157 | + return $deferred->promise(); |
161 | 158 | } |
162 | 159 |
|
163 | 160 | public function count() |
@@ -193,9 +190,28 @@ public function processQueue() |
193 | 190 | return; |
194 | 191 | } |
195 | 192 |
|
196 | | - $first = reset($this->queue); |
| 193 | + /* @var $deferred Deferred */ |
| 194 | + $deferred = reset($this->queue); |
197 | 195 | unset($this->queue[key($this->queue)]); |
198 | 196 |
|
199 | | - $first->resolve(); |
| 197 | + // once number of pending jobs is below concurrency limit again: |
| 198 | + // await this situation, invoke handler and await its resolution before invoking next queued job |
| 199 | + ++$this->pending; |
| 200 | + |
| 201 | + $promise = call_user_func_array($this->handler, $deferred->args); |
| 202 | + $deferred->pending = $promise; |
| 203 | + unset($deferred->args); |
| 204 | + |
| 205 | + // invoke handler and await its resolution before invoking next queued job |
| 206 | + $this->await($promise)->then( |
| 207 | + function ($result) use ($deferred) { |
| 208 | + unset($deferred->pending); |
| 209 | + $deferred->resolve($result); |
| 210 | + }, |
| 211 | + function ($e) use ($deferred) { |
| 212 | + unset($deferred->pending); |
| 213 | + $deferred->reject($e); |
| 214 | + } |
| 215 | + ); |
200 | 216 | } |
201 | 217 | } |
0 commit comments