diff --git a/server/SHServ/Controllers/DevicesRESTAPIController.php b/server/SHServ/Controllers/DevicesRESTAPIController.php index 7297a7e..5dec3ee 100644 --- a/server/SHServ/Controllers/DevicesRESTAPIController.php +++ b/server/SHServ/Controllers/DevicesRESTAPIController.php @@ -10,29 +10,50 @@ class DevicesRESTAPIController extends \SHServ\Middleware\Controller { protected function withScanLock(callable $callback) { $lockFile = dirname(__DIR__, 2) . '/Cache/scan.lock'; + $debugLog = dirname(__DIR__, 2) . '/Cache/scan-debug.log'; - // Если lock устарел (старше 120 сек) — считаем его мёртвым + $log = function($msg) use ($debugLog) { + $line = date('Y-m-d H:i:s') . ' [' . getmypid() . '] ' . $msg . PHP_EOL; + @file_put_contents($debugLog, $line, FILE_APPEND | LOCK_EX); + }; + if (file_exists($lockFile) && (time() - filemtime($lockFile)) > 120) { + $log('stale lock detected, unlinking'); @unlink($lockFile); } $fp = @fopen($lockFile, 'c+'); - if (!$fp || !flock($fp, LOCK_EX | LOCK_NB)) { + $log('lock busy (fp=' . var_export($fp, true) . '), returning 400'); return $this -> utils() -> response_error("scan_in_progress"); } ftruncate($fp, 0); fwrite($fp, getmypid()); fflush($fp); - touch($lockFile); // обновить mtime + touch($lockFile); - try { - return $callback(); - } finally { + $lockReleased = false; + $releaseLock = function() use ($fp, $lockFile, $log, &$lockReleased) { + if ($lockReleased) return; + $lockReleased = true; flock($fp, LOCK_UN); fclose($fp); @unlink($lockFile); + $log('lock released'); + }; + register_shutdown_function($releaseLock); + + try { + $log('lock acquired, starting scan'); + $result = $callback(); + $log('scan finished normally'); + return $result; + } catch (\Throwable $e) { + $log('scan exception: ' . $e -> getMessage()); + throw $e; + } finally { + $releaseLock(); } } diff --git a/server/SHServ/Tools/DeviceScanner.php b/server/SHServ/Tools/DeviceScanner.php index 14b361d..ba08e83 100644 --- a/server/SHServ/Tools/DeviceScanner.php +++ b/server/SHServ/Tools/DeviceScanner.php @@ -78,7 +78,7 @@ $batches = array_chunk($ips, self::BATCH_SIZE); foreach ($batches as $batch) { - if ((connection_status() !== CONNECTION_NORMAL)) { + if (connection_aborted() || connection_status() !== CONNECTION_NORMAL) { return $all_devices; } $batch_devices = $this -> scan_batch($batch, $port, $timeout); @@ -96,7 +96,7 @@ private function scan_batch(array $ips, int $port, float $timeout): array { $devices = $this -> scan_batch_multi($ips, $port, $timeout); - if ((connection_status() !== CONNECTION_NORMAL)) { + if (connection_aborted() || connection_status() !== CONNECTION_NORMAL) { return $devices; } @@ -156,7 +156,7 @@ break; } - if ((connection_status() !== CONNECTION_NORMAL)) { + if (connection_aborted() || connection_status() !== CONNECTION_NORMAL) { break; }