src/ProcessManager.php
public function closeSlaves($graceful = false, $onSlaveClosed = null)
    {
        if (!$onSlaveClosed) {
            // create a default no-op if callable is undefined
            $onSlaveClosed = function ($slave) {
            };
        }

        /*
         * NB: we don't lock slave reload with a semaphore, since this could cause
         * improper reloads when long reload timeouts and multiple code edits are combined.
         */

        $this->slavesToReload = [];

        foreach ($this->slaves->getByStatus(Slave::ANY) as $slave) {
            /** @var Slave $slave */

            /*
             * Attach the callable to the connection close event, because locked workers are closed via RequestHandler.
             * For now, we still need to call onClosed() in other circumstances as ProcessManager->closeSlave() removes
             * all close handlers.
             */
            $connection = $slave->getConnection();

            if ($connection) {
                // todo: connection has to be null-checked, because of race conditions with many workers. fixed in #366
                $connection->on('close', function () use ($onSlaveClosed, $slave) {
                    $onSlaveClosed($slave);
                });
            }

            if ($graceful && $slave->getStatus() === Slave::BUSY) {
                if ($this->output->isVeryVerbose()) {
                    $this->output->writeln(sprintf('Waiting for worker #%d to finish', $slave->getPort()));
                }

                $slave->lock();
                $this->slavesToReload[$slave->getPort()] = $slave;
            } elseif ($graceful && $slave->getStatus() === Slave::LOCKED) {
                if ($this->output->isVeryVerbose()) {
                    $this->output->writeln(
                        sprintf(
                            'Still waiting for worker #%d to finish from an earlier reload',
                            $slave->getPort()
                        )
                    );
                }
                $this->slavesToReload[$slave->getPort()] = $slave;
            } else {
                $this->closeSlave($slave);
                $onSlaveClosed($slave);
            }
        }

        if ($this->reloadTimeoutTimer !== null) {
            $this->loop->cancelTimer($this->reloadTimeoutTimer);
        }

        $this->reloadTimeoutTimer = $this->loop->addTimer($this->reloadTimeout, function () use ($onSlaveClosed) {
            if ($this->slavesToReload && $this->output->isVeryVerbose()) {
                $this->output->writeln('Cleaning up workers that exceeded the graceful reload timeout.');
            }

            foreach ($this->slavesToReload as $slave) {
                $this->output->writeln(
                    sprintf(
                        '<error>Worker #%d exceeded the graceful reload timeout and was killed.</error>',
                        $slave->getPort()
                    )
                );

                $this->closeSlave($slave);
                $onSlaveClosed($slave);
            }
        });
    }
public function closeSlaves($graceful = false, $onSlaveClosed = null)
    {
        if (!$onSlaveClosed) {
            // create a default no-op if callable is undefined
            $onSlaveClosed = function ($slave) {
            };
        }

        /*
         * NB: we don't lock slave reload with a semaphore, since this could cause
         * improper reloads when long reload timeouts and multiple code edits are combined.
         */

        $this->slavesToReload = [];

        foreach ($this->slaves->getByStatus(Slave::ANY) as $slave) {
            /** @var Slave $slave */

            /*
             * Attach the callable to the connection close event, because locked workers are closed via RequestHandler.
             * For now, we still need to call onClosed() in other circumstances as ProcessManager->closeSlave() removes
             * all close handlers.
             */
            $connection = $slave->getConnection();

            if ($connection) {
                // todo: connection has to be null-checked, because of race conditions with many workers. fixed in #366
                $connection->on('close', function () use ($onSlaveClosed, $slave) {
                    $onSlaveClosed($slave);
                });
            }

            if ($graceful && $slave->getStatus() === Slave::BUSY) {
                if ($this->output->isVeryVerbose()) {
                    $this->output->writeln(sprintf('Waiting for worker #%d to finish', $slave->getPort()));
                }

                $slave->lock();
                $this->slavesToReload[$slave->getPort()] = $slave;
            } elseif ($graceful && $slave->getStatus() === Slave::LOCKED) {
                if ($this->output->isVeryVerbose()) {
                    $this->output->writeln(
                        sprintf(
                            'Still waiting for worker #%d to finish from an earlier reload',
                            $slave->getPort()
                        )
                    );
                }
                $this->slavesToReload[$slave->getPort()] = $slave;
            } else {
                $this->closeSlave($slave);
                $onSlaveClosed($slave);
            }
        }

        if ($this->reloadTimeoutTimer !== null) {
            $this->loop->cancelTimer($this->reloadTimeoutTimer);
        }

        $this->reloadTimeoutTimer = $this->loop->addTimer($this->reloadTimeout, function () use ($onSlaveClosed) {
            if ($this->slavesToReload && $this->output->isVeryVerbose()) {
                $this->output->writeln('Cleaning up workers that exceeded the graceful reload timeout.');
            }

            foreach ($this->slavesToReload as $slave) {
                $this->output->writeln(
                    sprintf(
                        '<error>Worker #%d exceeded the graceful reload timeout and was killed.</error>',
                        $slave->getPort()
                    )
                );

                $this->closeSlave($slave);
                $onSlaveClosed($slave);
            }
        });
    }
public function closeSlaves ( $ graceful = false , $ onSlaveClosed = null ) { if ( ! $ onSlaveClosed ) { // create a default no-op if callable is undefined $ onSlaveClosed = function ( $ slave ) { } ; } /*
         * NB: we don't lock slave reload with a semaphore, since this could cause
         * improper reloads when long reload timeouts and multiple code edits are combined.
         */ $ this -> slavesToReload = [ ] ; foreach ( $ this -> slaves -> getByStatus ( Slave :: ANY ) as $ slave ) { /** @var Slave $slave */ /*
             * Attach the callable to the connection close event, because locked workers are closed via RequestHandler.
             * For now, we still need to call onClosed() in other circumstances as ProcessManager->closeSlave() removes
             * all close handlers.
             */ $ connection = $ slave -> getConnection ( ) ; if ( $ connection ) { // todo: connection has to be null-checked, because of race conditions with many workers. fixed in #366 $ connection -> on ( 'close' , function ( ) use ( $ onSlaveClosed , $ slave ) { $ onSlaveClosed ( $ slave ) ; } ) ; } if ( $ graceful && $ slave -> getStatus ( ) === Slave :: BUSY ) { if ( $ this -> output -> isVeryVerbose ( ) ) { $ this -> output -> writeln ( sprintf ( 'Waiting for worker #%d to finish' , $ slave -> getPort ( ) ) ) ; } $ slave -> lock ( ) ; $ this -> slavesToReload [ $ slave -> getPort ( ) ] = $ slave ; } elseif ( $ graceful && $ slave -> getStatus ( ) === Slave :: LOCKED ) { if ( $ this -> output -> isVeryVerbose ( ) ) { $ this -> output -> writeln ( sprintf ( 'Still waiting for worker #%d to finish from an earlier reload' , $ slave -> getPort ( ) ) ) ; } $ this -> slavesToReload [ $ slave -> getPort ( ) ] = $ slave ; } else { $ this -> closeSlave ( $ slave ) ; $ onSlaveClosed ( $ slave ) ; } } if ( $ this -> reloadTimeoutTimer !== null ) { $ this -> loop -> cancelTimer ( $ this -> reloadTimeoutTimer ) ; } $ this -> reloadTimeoutTimer = $ this -> loop -> addTimer ( $ this -> reloadTimeout , function ( ) use ( $ onSlaveClosed ) { if ( $ this -> slavesToReload && $ this -> output -> isVeryVerbose ( ) ) { $ this -> output -> writeln ( 'Cleaning up workers that exceeded the graceful reload timeout.' ) ; } foreach ( $ this -> slavesToReload as $ slave ) { $ this -> output -> writeln ( sprintf ( '<error>Worker #%d exceeded the graceful reload timeout and was killed.</error>' , $ slave -> getPort ( ) ) ) ; $ this -> closeSlave ( $ slave ) ; $ onSlaveClosed ( $ slave ) ; } } ) ; }
Closes all slaves and fires a user-defined callback for each slave that is closed.

If $graceful is false, slaves are closed unconditionally, regardless of their current status.

If $graceful is true, workers that are busy are put into a locked state, and will be closed after serving the
current request. If a reload-timeout is configured with a non-negative value, any workers that exceed this value
in seconds will be killed.

@param bool $graceful
@param callable $onSlaveClosed A closure that is called for each worker.
Closes all slaves and fires a user - defined callback for each slave that is closed .