Skip to content

Instantly share code, notes, and snippets.

@7-zete-7
Created November 29, 2024 21:45
Show Gist options
  • Save 7-zete-7/81f7b83e384b15726fcf25d1515aced1 to your computer and use it in GitHub Desktop.
Save 7-zete-7/81f7b83e384b15726fcf25d1515aced1 to your computer and use it in GitHub Desktop.
Doctrine DBAL Ping Connection Middleware

Requirements

  • Installed iputils-ping APT-package (for Debian)
  • PHP >= 8.0
  • Installed doctrine/dbal, symfony/process and doctrine/doctrine-bundle Composer packages
<?php
declare(strict_types=1);
namespace App\Doctrine\DBAL\Middleware\PingConnection;
use Doctrine\DBAL\ConnectionException;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\Exception as DriverException;
use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware;
use SensitiveParameter;
use Symfony\Component\Process\Process;
final class Driver extends AbstractDriverMiddleware
{
public function __construct(
DriverInterface $wrappedDriver,
private readonly int $timeout,
) {
parent::__construct($wrappedDriver);
}
/**
* @throws ConnectionException
* @throws DriverException
*/
public function connect(#[SensitiveParameter] array $params): Connection
{
if (!$this->pingConnection($params['host'])) {
throw new ConnectionException(\sprintf('Host "%s" is unreachable.', $params['host']));
}
return parent::connect($params);
}
private function pingConnection(string $host): bool
{
$process = new Process([
'ping', // man ping (8)
// Stop after sending count ECHO_REQUEST packets.
// With deadline option, ping waits for count ECHO_REPLY packets,
// until the timeout expires.
'-c1',
// Quiet output. Nothing is displayed except the summary lines
// at startup time and when finished.
'-q',
// Specify a timeout, in seconds, before ping exits regardless
// of how many packets have been sent or received.
// In this case ping does not stop after count packet are sent,
// it waits either for deadline expire or until count probes
// are answered or for some error notification from network.
\sprintf('-w%d', $this->timeout),
// destination
$host,
]);
$process->setTimeout($this->timeout + 1);
$process->disableOutput();
$process->run();
return $process->isSuccessful();
}
}
<?php
declare(strict_types=1);
namespace App\Doctrine\DBAL\Middleware\PingConnection;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsMiddleware;
use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface;
#[AsMiddleware(priority: 1024)]
class Middleware implements MiddlewareInterface
{
public function __construct(
private readonly int $timeout = 5,
) {
}
public function wrap(DriverInterface $driver): DriverInterface
{
return new Driver($driver, $this->timeout);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment