Skip to content

Instantly share code, notes, and snippets.

@hotta

hotta/pg-persist.php

Last active Jun 17, 2021
Embed
What would you like to do?
Pgpool 通常稼働のため、Pgpool を定期的にポーリングしてDB接続を維持する
#!/usr/bin/php
<?php
//
// pg-persist.php
// pgpool ではクライアントからの接続がない場合は障害時でもフェイルオーバー
// しないため、DB接続を維持するため(だけ)のスクリプトを準備した。
// cron から起動する場合はバックグラウンド起動とすること。
// テスト側でのみ必要。
//
// https://www.php.net/manual/ja/ref.pdo-pgsql.connection.php
// https://www.php.net/manual/ja/pdo.connections.php
//
declare(ticks = 1); // シグナルハンドラ利用時に必要
class MyClass {
const HOST = "pgpool-vip";
const PORT = "9999";
const DBNAME = "postgres";
const DBUSER = "vagrant";
const DBPASS = "";
const INTERVAL = 10; // 単位:秒
const MAILTO = "mhotta@example.com"; // メール通知先
const SQL = "SELECT COUNT(*) FROM pg_user"; // 値を1つだけ返す SQL を指定する
private $dbh = null;
private $PIDFILE = null;
private $in_cron = false;
// -------------------
// 初期化
// -------------------
public function __construct() {
if (! isset($_SERVER['TERM']) && ! isset($_SERVER['VSCODE_AGENT_FOLDER'])) {
$this->in_cron = true;
}
$PIDDIR = getenv("HOME") . "/.pg-persist";
$this->PIDFILE = "$PIDDIR/pg-persist.pid";
if (! is_dir($PIDDIR)) {
mkdir($PIDDIR);
}
if (file_exists($this->PIDFILE)) {
$pid = file_get_contents($this->PIDFILE); // PID 読み込み
if (! $this->in_cron) {
printf("Another process seems to be running: pid = %s\n", $pid);
}
exit(0);
}
file_put_contents($this->PIDFILE, getmypid());
pcntl_signal(SIGTERM, [ $this, "sig_handler"] );
pcntl_signal(SIGINT, [ $this, "sig_handler"] );
} // __construct()
// -------------------
// シグナルハンドラ
// -------------------
public function sig_handler($signo) {
switch ($signo) {
case SIGTERM:
case SIGINT:
unlink($this->PIDFILE); // PID ファイル削除
exit(0);
}
}
// -------------------
// メール送信&終了
// -------------------
private function sendmail($msg = "") {
if (! $this->in_cron) {
printf("%s\n", $msg);
} else {
mail(self::MAILTO, "pg-persist.php", $msg);
}
exit(-1);
} // sendmail()
// -------------------
// DB接続
// -------------------
private function connect() {
$dsn = sprintf("pgsql:host=%s;port=%s;dbname=%s",
self::HOST, self::PORT, self::DBNAME);
try {
$this->dbh = new PDO($dsn, self::DBUSER, self::DBPASS, [
PDO::ATTR_PERSISTENT => true // 持続的接続
]);
} catch (PDOException $e) {
// print_r($e);
unlink($this->PIDFILE); // PID ファイル削除
$msg = $e->errorInfo[2];
$this->sendmail($msg);
}
} // connect()
// -------------------
// DBポーリング
// -------------------
private function poll() {
if (! $this->dbh) { // pgpoolから切断された
$this->connect();
}
try {
foreach ($this->dbh->query(self::SQL) as $row) {
if (! $this->in_cron) {
print_r($row['0']);
}
}
} catch (PDOException $e) {
unlink($PIDFILE); // PID ファイル削除
$this->sendmail("Could not exec to PDO");
}
} // poll()
// -------------------
// メインループ
// -------------------
public function run() {
while (1) {
$this->poll();
sleep(self::INTERVAL);
}
} // run()
} // class MyClass
$x = new MyClass();
$x->run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment