public function run()
    {
        $this->setupSignalHandlers();

        $procs = [];
        while (true) {
            $jobs = $this->runner->getJobs();
            foreach ($jobs as $job) {
                if (! array_key_exists($job->identifier(), $procs)) {
                    $procs[$job->identifier()] = [];
                }
                while (count($procs[$job->identifier()]) > $job->numWorkers()) {
                    // Stopping an excessive child.
                    echo 'Stopping an excessive child.' . PHP_EOL;
                    $proc = array_pop($procs[$job->identifier()]);
                    $status = proc_get_status($proc);
                    // Keep sending SIGTERM until the child exits.
                    while ($status['running'] === true) {
                        @proc_terminate($proc);
                        usleep(50000);
                        $status = proc_get_status($proc);
                    }
                    @proc_close($proc);
                }
                for ($i = 0; $i < $job->numWorkers(); $i++) {
                    $needStart = false;
                    if (array_key_exists($i, $procs[$job->identifier()])) {
                        $status = proc_get_status($procs[$job->identifier()][$i]);
                        if ($status['running'] !== true) {
                            $needStart = true;
                        }
                    } else {
                        $needStart = true;
                    }
                    if ($needStart) {
                        echo 'Starting a child.' . PHP_EOL;
                        $procs[$job->identifier()][$i] = proc_open(
                            sprintf('%s %d', $this->command, $job->id()),
                            $this->descriptorSpec,
                            $pipes
                        );
                    }
                }
            }
            usleep(1000000); // Reload the config after 1 second
            pcntl_signal_dispatch();
            if ($this->shutdown) {
                echo 'Shutting down, waiting for the children' . PHP_EOL;
                foreach ($procs as $k => $v) {
                    foreach ($v as $proc) {
                        $status = proc_get_status($proc);
                        // Keep sending SIGTERM until the child exits.
                        while ($status['running'] === true) {
                            @proc_terminate($proc);
                            usleep(50000);
                            $status = proc_get_status($proc);
                        }
                        @proc_close($proc);
                    }
                }
                echo 'BatchDaemon exiting' . PHP_EOL;
                exit;
            }
            // Reload the config
            $this->runner->loadConfig();
        }
    }