= CURDATE() "; $stmt = $pdo->prepare($sqlList); $stmt->execute(); $mikrotiks = $stmt->fetchAll(PDO::FETCH_ASSOC); $pdo = null; if (empty($mikrotiks)) { echo "[" . date('Y-m-d H:i:s') . "] Tidak ada data MikroTik.\n"; exit(0); } echo "Total MikroTik: " . count($mikrotiks) . "\n"; // ================================ // Fork parallel // ================================ $child_pids = []; $outfiles = []; foreach ($mikrotiks as $data) { while (count($child_pids) >= $max_processes) { foreach ($child_pids as $key => $pid) { if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { unset($child_pids[$key]); } } usleep(100000); } $safeId = preg_replace('~[^A-Za-z0-9_\-]~', '_', $data['board_id']); $outfile = $tmpDir . "/mt_" . $safeId . "_" . uniqid() . ".json"; $outfiles[] = $outfile; $pid = pcntl_fork(); if ($pid == -1) { echo "[" . date('Y-m-d H:i:s') . "] Gagal fork.\n"; continue; } elseif ($pid) { $child_pids[] = $pid; } else { process_mikrotik_child($data, $timeout_api, $outfile); exit(0); } } // Tunggu semua child selesai foreach ($child_pids as $pid) { pcntl_waitpid($pid, $status); } echo "[" . date('Y-m-d H:i:s') . "] Semua child selesai. Mulai update DB...\n"; // ================================ // Update DB // ================================ include "/www/wwwroot/bilspro/config/connect.php"; $pdo->exec("SET time_zone = '+07:00'"); $updated = 0; $skipped = 0; $failed = 0; try { $pdo->beginTransaction(); $updateSql = " UPDATE setting_mikrotik SET uptime = :ut, board_name = :bm, status = :st, last_time = NOW() WHERE id = :id "; $updateStmt = $pdo->prepare($updateSql); foreach ($outfiles as $file) { if (!is_file($file) || filesize($file) == 0) { $failed++; continue; } $json = file_get_contents($file); @unlink($file); $row = json_decode($json, true); if (!$row || !isset($row['id'], $row['status'])) { $failed++; continue; } $params = [ ':ut' => $row['uptime'] ?? '', ':bm' => $row['board_name'] ?? '', ':st' => $row['status'], ':id' => $row['id'], ]; $updateStmt->execute($params); if ($updateStmt->rowCount() > 0) { echo "[" . date('H:i:s') . "] [UPDATE] {$row['board_id']} - {$row['status']}\n"; $updated++; } else { $skipped++; } } $pdo->commit(); echo "[" . date('Y-m-d H:i:s') . "] Commit berhasil.\n"; } catch (Exception $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } echo "[ERROR] " . $e->getMessage() . "\n"; } $pdo = null; echo "[" . date('Y-m-d H:i:s') . "] Selesai. OK: {$updated}, SKIP: {$skipped}, FAIL: {$failed}\n"; // ================================ // CHILD PROCESS // ================================ function process_mikrotik_child(array $data, int $timeout_api, string $outfile): void { $API = new RouterosAPI(); $API->debug = false; $API->timeout = $timeout_api; $result = [ 'id' => $data['id'], 'board_id' => $data['board_id'], 'status' => 'Disconnected', 'board_name' => '', 'uptime' => '', ]; if ($API->connect2($data['ip_address'], $data['username'], $data['password'], $data['port_api'])) { $sys = $API->comm("/system/resource/print"); if (is_array($sys) && !empty($sys[0])) { $result['board_name'] = $sys[0]['board-name'] ?? ''; $result['uptime'] = $sys[0]['uptime'] ?? ''; } $result['status'] = 'Connected'; $API->disconnect(); echo "[" . date('H:i:s') . "] [OK] {$data['ip_address']} [{$data['nama_server']}] [{$data['nama']}]\n"; } else { echo "[" . date('H:i:s') . "] [FAIL] {$data['ip_address']} [{$data['nama_server']}] [{$data['nama']}]\n"; } file_put_contents($outfile, json_encode($result), LOCK_EX); }