DATA/WATCHMAN/watchman/daemon_watchman_trading_sub.php
#!/usr/bin/php
<?php
/**
 * ============================================================
 * daemon_watchman_sub.php
 * - 2중 감시용 서브 워치맨
 * - 단 하나만 감시함: daemon_watchman_main.php
 * - main 데몬이 죽으면 즉시 살림
 * - PID 파일 사용 없음 (DB 기반)
 * - 관제: daemon_record 테이블
 * - 루프: 3초
 * ============================================================
 */

error_reporting(E_ALL);
ini_set('display_errors', 1);
date_default_timezone_set('Asia/Seoul');

// ------------------------------------------------------------
// 1. 기본 설정
// ------------------------------------------------------------
$THIS_FILE = __FILE__;
$DAEMON_ID = pathinfo($THIS_FILE, PATHINFO_FILENAME);  // daemon_watchman_sub

$WATCH_DIR = "/home/www/DATA/UPBIT/daemon/watchman";
$TARGET_MAIN = "daemon_watchman_trading_main.php";
$TARGET_PATH = $WATCH_DIR . "/" . $TARGET_MAIN;

// ------------------------------------------------------------
// 2. DB 연결 함수
// ------------------------------------------------------------
function get_db() {
    require "/home/www/DB/db_upbit.php"; // $db_upbit
    $pdo = $db_upbit;
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $pdo;
}

$pdo = get_db();

// ------------------------------------------------------------
// 3. 관제 기록 (daemon_record)
// ------------------------------------------------------------
function report_status($pdo, $DAEMON_ID) {
    $stmt = $pdo->prepare("
        INSERT INTO daemon_record (
            d_id, d_category, d_pid, d_status,
            d_heartbeat, d_ip, d_start_time, d_memo, d_kill_flag
        )
        VALUES (
            :id, 'WATCHMAN', :pid, 'RUNNING',
            NOW(), 'CLI', NOW(), 'SUB WATCHMAN', 0
        )
        ON DUPLICATE KEY UPDATE
            d_pid       = VALUES(d_pid),
            d_status    = 'RUNNING',
            d_heartbeat = NOW()
    ");
    $stmt->execute([
        ':id'  => $DAEMON_ID,
        ':pid' => getmypid()
    ]);
}

// ------------------------------------------------------------
// 4. 프로세스 생존 여부 체크
// ------------------------------------------------------------
function is_alive($pid) {
    return ($pid && posix_kill((int)$pid, 0));
}

// ------------------------------------------------------------
// 5. main 데몬 실행
// ------------------------------------------------------------
function run_main_daemon($path) {
    $cmd = "php {$path} > /dev/null 2>&1 & echo $!";
    $pid = trim(shell_exec($cmd));
    return ctype_digit($pid) ? (int)$pid : null;
}

// ------------------------------------------------------------
// 6. DB에서 대상 데몬 PID 가져오기
// ------------------------------------------------------------
function get_target_pid($pdo, $target_id) {
    $stmt = $pdo->prepare("SELECT d_pid FROM daemon_record WHERE d_id = :id LIMIT 1");
    $stmt->execute([':id' => $target_id]);
    $pid = $stmt->fetchColumn();
    return $pid ? (int)$pid : null;
}

// ------------------------------------------------------------
// INIT
// ------------------------------------------------------------
echo "==================================================\n";
echo "[{$DAEMON_ID}] SUB WATCHMAN STARTED\n";
echo "TARGET: {$TARGET_MAIN}\n";
echo "==================================================\n";


// ------------------------------------------------------------
// MAIN LOOP — 3초 감시
// ------------------------------------------------------------
while (true) {
    try {
        $pdo = get_db();  // ensure connection

        // 워치맨 상태 저장
        report_status($pdo, $DAEMON_ID);

        // main 데몬 PID 조회
        $main_pid = get_target_pid($pdo, "daemon_watchman_main");
        $alive = is_alive($main_pid);

        if (!$alive) {
            echo "[SUB] MAIN DEAD — RESTARTING...\n";

            // 재실행
            $new_pid = run_main_daemon($TARGET_PATH);

            if ($new_pid) {
                // DB 갱신
                $stmt = $pdo->prepare("
                    INSERT INTO daemon_record (
                        d_id, d_category, d_pid, d_status,
                        d_heartbeat, d_ip, d_start_time, d_memo, d_kill_flag
                    )
                    VALUES (
                        'daemon_watchman_main', 'WATCHMAN', :pid, 'RUNNING',
                        NOW(), 'CLI', NOW(), 'MAIN WATCHMAN', 0
                    )
                    ON DUPLICATE KEY UPDATE
                        d_pid       = VALUES(d_pid),
                        d_status    = 'RUNNING',
                        d_heartbeat = NOW()
                ");
                $stmt->execute([':pid' => $new_pid]);

                echo "[SUB] MAIN RESTARTED | PID={$new_pid}\n";
            } else {
                echo "[SUB] MAIN RESTART FAILED\n";
            }
        }

    } catch (Exception $e) {
        echo "[ERROR] " . $e->getMessage() . "\n";
        sleep(2);
    }

    sleep(3);
}

?>