src/Pool.php
function destroy() {
        return (new \React\Promise\Promise(function (callable $resolve, callable $reject) {
            foreach($this->workers as $id => $worker) {
                if(!$worker->isRunning()) {
                    $this->messenger->removeWorkerSocket($worker);
                    unset($this->workers[$id]);
                }
            }
            
            $this->busyWorkers->clear();
            while($this->freeWorkers->count() > 0) {
                $this->freeWorkers->dequeue();
            }
            
            while($this->workQueue->count() > 0) {
                $this->workQueue->dequeue();
            }
            
            if(\count($this->workers) === 0) {
                $this->cancelTimer();
                $this->messenger->destroy();
                
                return $resolve();
            }
            
            $this->attachTimer();
            
            $timer = null;
            $workers = $this->workers;
            
            $listener = function () use ($resolve, $workers, &$listener, &$timer) {
                if(empty($this->workers)) {
                    $this->removeListener('exitWorker', $listener);
                    
                    if($timer) {
                        $this->loop->cancelTimer($timer);
                    }
                    
                    $this->cancelTimer();
                    $this->messenger->destroy();
                    
                    /** @var \CharlotteDunois\Phoebe\Worker  $worker */
                    while($worker = \array_shift($workers)) {
                        $worker->join();
                    }
                    
                    $resolve();
                }
            };
            
            $timeout = \count($workers) * ($this->options['workerShutdownGrace'] ?? 2);
            $timeout = ($timeout > 0 ? $timeout : ($this->options['workerShutdownGrace'] ?? 2));
            
            $timer = $this->loop->addTimer($timeout, function () use ($reject, &$listener) {
                $this->removeListener('exitWorker', $listener);
                
                $this->cancelTimer();
                $this->messenger->destroy();
                
                $reject(new \RuntimeException('Destroying pool takes too long'));
            });
            
            /** @var \CharlotteDunois\Phoebe\InternalTask  $task */
            foreach($this->tasks as $task) {
                $task->getDeferred()->reject((new \RuntimeException('Shutting down pool')));
                unset($task);
            }
            
            $this->tasks->clear();
            
            foreach($this->workers as $worker) {
                $this->stopWorker($worker);
            }
            
            $this->on('exitWorker', $listener);
        }));
    }
function destroy() {
        return (new \React\Promise\Promise(function (callable $resolve, callable $reject) {
            foreach($this->workers as $id => $worker) {
                if(!$worker->isRunning()) {
                    $this->messenger->removeWorkerSocket($worker);
                    unset($this->workers[$id]);
                }
            }
            
            $this->busyWorkers->clear();
            while($this->freeWorkers->count() > 0) {
                $this->freeWorkers->dequeue();
            }
            
            while($this->workQueue->count() > 0) {
                $this->workQueue->dequeue();
            }
            
            if(\count($this->workers) === 0) {
                $this->cancelTimer();
                $this->messenger->destroy();
                
                return $resolve();
            }
            
            $this->attachTimer();
            
            $timer = null;
            $workers = $this->workers;
            
            $listener = function () use ($resolve, $workers, &$listener, &$timer) {
                if(empty($this->workers)) {
                    $this->removeListener('exitWorker', $listener);
                    
                    if($timer) {
                        $this->loop->cancelTimer($timer);
                    }
                    
                    $this->cancelTimer();
                    $this->messenger->destroy();
                    
                    /** @var \CharlotteDunois\Phoebe\Worker  $worker */
                    while($worker = \array_shift($workers)) {
                        $worker->join();
                    }
                    
                    $resolve();
                }
            };
            
            $timeout = \count($workers) * ($this->options['workerShutdownGrace'] ?? 2);
            $timeout = ($timeout > 0 ? $timeout : ($this->options['workerShutdownGrace'] ?? 2));
            
            $timer = $this->loop->addTimer($timeout, function () use ($reject, &$listener) {
                $this->removeListener('exitWorker', $listener);
                
                $this->cancelTimer();
                $this->messenger->destroy();
                
                $reject(new \RuntimeException('Destroying pool takes too long'));
            });
            
            /** @var \CharlotteDunois\Phoebe\InternalTask  $task */
            foreach($this->tasks as $task) {
                $task->getDeferred()->reject((new \RuntimeException('Shutting down pool')));
                unset($task);
            }
            
            $this->tasks->clear();
            
            foreach($this->workers as $worker) {
                $this->stopWorker($worker);
            }
            
            $this->on('exitWorker', $listener);
        }));
    }
Destroys the pool (cancels the timer and sends shutdown signals to all workers **asynchronously** but joins them synchronously).
If the operation takes far too long, the promise will be rejected.
Be cautious, if this happens, you **MUST** make the process exit under all circumstances and report this.
@return \React\Promise\ExtendedPromiseInterface