iT邦幫忙

0

HardwareMonitor - Day 08|從手動按刷新到自動巡檢:監控排程與並行控制

  • 分享至 

  • xImage
  •  

Day 08|從手動按刷新到自動巡檢:監控排程與並行控制

第一版完成後,我很開心地按下「立即刷新」,結果頁面轉了好幾秒,看起來就像當機。原因很單純:程式正在逐台連線、檢查網站、讀取 RDP 狀態,瀏覽器只能原地等待。只有幾台機器時還能忍受,但設備繼續增加後,手動刷新與同步等待一定撐不住。

所以 HeadlessRuntime 負責看時間,並把慢工作交給背景執行緒。輪詢、RDP、網站與報表各自有 lock:同一件事還沒完成,就不重複開第二次;不同工作則能同時進行。按下立即刷新時,請求先進 queue,等收集完成再回覆。

我一開始以為多開執行緒就好,後來才明白重點是避免重複工作。_start_poll 和 _collect_refresh_requests 是這個轉折的核心。

本篇學習重點

  • 將耗時的監控巡檢移到背景執行。
  • 使用非阻塞鎖避免同一輪監控重複啟動。
  • 確保發生例外時仍能釋放鎖並回報結果。

重點程式碼:非阻塞鎖避免重複輪詢

def _start_poll(self):
    if not self._poll_lock.acquire(False):
        return
    threading.Thread(target=self._poll, daemon=True).start()

def _poll(self):
    try:
        self.monitor.poll()
    finally:
        self._poll_lock.release()

finally 是關鍵;少了它,一次例外就可能讓排程永久停止。

程式碼運作方式

  1. acquire(False) 嘗試取得鎖,但不等待;已有輪詢時便直接返回。
  2. 成功取得鎖後,以 daemon thread 執行慢速監控,不阻塞主迴圈。
  3. 不論 poll 成功或拋出例外,finally 都會釋放鎖。

實際專案還會保存結果並通知等待刷新者;這段特別留下最容易造成排程卡死的鎖定生命週期。

實際使用範例

runtime._start_poll()  # 成功取得鎖,啟動背景工作
runtime._start_poll()  # 前一輪尚未完成,直接返回

reply = queue.Queue()
runtime.refresh_queue.put(reply)
result = reply.get(timeout=30)
print(result["status"])

範例同時呈現排程防重入與使用者等待立即刷新的兩條路徑。

實作時遇到的問題

曾經有兩位使用者同時按下刷新,系統便啟動兩輪主機掃描,不但變慢,還同時寫入快照。修復時我替每類背景工作加入獨立 lock,執行中的輪詢不再重入;刷新請求則放入 queue,共同等待同一輪結果。另一個 Bug 是工作拋出例外後 lock 沒被釋放,導致排程永久停止,因此釋放動作必須放在 finally,確保成功或失敗都能進入下一輪。

今日心得

今天我學到,多開執行緒不是答案,工作生命週期與重入控制才是關鍵。下一篇會保存快照與歷史,讓系統開始理解過去。

連載頁
HardwareMonitor目錄

認識我們
聯繫我們


*提醒邦友,使用第三方服務/API 時,請務必評估資安風險與隱私保護
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言