public function start(int $timeout_ms = 3000): void
    {
        $port = $this->config->getPort();

        $this->logger->notice("Starting standalone server on port $port.");

        if ($this->isStarted()) {
            $this->logger->notice('Standalone server already running, skipping start.');

            return;
        }

        if (!$this->portTester->isAvailable('localhost', $port, 'http')) {
            $msg = "Cannot start server on port '$port', it's already in use.";
            $this->logger->error("Start failed: $msg");
            throw new Exception\PortUnavailableException($msg);
        }

        $command = $this->getCommand();

        $log_file = $this->config->getLogFile();
        $pid_file = $this->config->getPidFile();
        $cmd = sprintf('%s > %s 2>&1 & echo $! > %s', $command, $log_file, $pid_file);

        $this->logger->debug("Start server with: $cmd");
        exec($cmd);

        if (!file_exists($pid_file)) {
            $msg = "Server not started, pid file was not created in '$pid_file'";
            $this->logger->error("Start failed: $msg");
            throw new Exception\RuntimeException($msg);
        }
        if (!file_exists($log_file)) {
            $msg = "Server not started, log file was not created in '$log_file'";
            $this->logger->error("Start failed: $msg");
            throw new Exception\RuntimeException($msg);
        }

        // Loop for waiting correct start of phpjavabridge
        $started = false;
        $iterations = 0;
        $refresh_us = 100 * 1000; // 100ms
        $timeout_us = $timeout_ms * 1000;
        $max_iterations = ceil($timeout_us / min([$refresh_us, $timeout_us]));

        while (!$started || $iterations > $max_iterations) {
            usleep($refresh_us);
            $log_file_content = file_get_contents($log_file);
            if (preg_match('/Exception/', $log_file_content)) {
                $msg = "Cannot start standalone server on port '$port', reason:\n";
                $msg .= $log_file_content;
                $this->logger->error("Start failed: $msg");
                throw new Exception\RuntimeException($msg);
            }

            $log_file_content = file_get_contents($log_file);
            if (preg_match('/JavaBridgeRunner started on/', $log_file_content)) {
                $started = true;
            }
            ++$iterations;
        }
        if (!$started) {
            $msg = "Standalone server probably not started, timeout '$timeout_ms' reached before getting output";
            $this->logger->error("Start failed: $msg");
            throw new Exception\RuntimeException($msg);
        }
        $this->started = true;
    }