<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Forever npm｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/forever-npm/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>Forever npm｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/forever-npm/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Sat, 10 Oct 2020 10:44:44 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/forever-npm/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>【Day25】排程 - 用forever套件來控管排程，背景執行才是王道！</title>
      <link>https://deanlin.net/blog/202010/fb-ig-crawler-day-25/</link>
      <pubDate>Sat, 10 Oct 2020 10:44:44 +0800</pubDate>
      <guid>https://deanlin.net/blog/202010/fb-ig-crawler-day-25/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>技術教學</category>
      <description>我想很多人跟我一樣不小心順手把終端機(Terminal)給關了 (或是很乾脆地把 VScode 關了)，但視窗關閉後排程其實還在背景持續運行，下面提供一個快速的解決方案：</description>
      <media:content url="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/cover_hu_78c86479e941f53f.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>如果一個套件無法解決問題，那就用兩個吧！</p>
</blockquote>
<h2 id="思考一下昨天的排程有什麼缺點">思考一下昨天的排程有什麼缺點<a class="h-anchor" href="#%e6%80%9d%e8%80%83%e4%b8%80%e4%b8%8b%e6%98%a8%e5%a4%a9%e7%9a%84%e6%8e%92%e7%a8%8b%e6%9c%89%e4%bb%80%e9%ba%bc%e7%bc%ba%e9%bb%9e" aria-label="這個段落的連結"></a></h2>
<p><strong>昨天完成的排程其實有幾個缺點：</strong></p>
<ol>
<li>在終端機(Terminal)執行排程後你<mark>必須保持開啟</mark>的狀態你才知道他有沒有正確執行</li>
<li>如果不小心把執行排程的終端機(Terminal)關掉你會很困擾，因為你關掉的是終端機不是排程，<mark>你想關掉排程還要另外下幾個指令</mark></li>
<li>管理困難，<mark>啟動、停止、重啟你都要在專案資料夾</mark>下處理</li>
<li>如果運行過程中程式<mark>意外關閉需要手動重開</mark></li>
<li><mark>在排程運行中你修改爬蟲json裡面的粉專列表是無效的</mark>，實驗看看就會發現觸發爬蟲時跑的是舊版的粉專列表</li>
</ol>
<hr>
<h2 id="今日目標">今日目標<a class="h-anchor" href="#%e4%bb%8a%e6%97%a5%e7%9b%ae%e6%a8%99" aria-label="這個段落的連結"></a></h2>
<ol>
<li>砍掉執行中的排程</li>
<li>使用套件 <code>forever</code> 來管理排程</li>
<li>在 package.json 中加入驅動 forever 的 scripts</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-砍掉執行中的排程">1. 砍掉執行中的排程<a class="h-anchor" href="#1-%e7%a0%8d%e6%8e%89%e5%9f%b7%e8%a1%8c%e4%b8%ad%e7%9a%84%e6%8e%92%e7%a8%8b" aria-label="這個段落的連結"></a></h2>
<p>我想很多人跟我一樣不小心順手把終端機(Terminal)給關了 (或是很乾脆地把 VScode 關了)，但<mark>視窗關閉後排程其實還在背景持續運行</mark>，下面提供一個快速的解決方案：</p>
<pre tabindex="0"><code>ps aux | grep [搜尋關鍵字]
kill [程式的PID]
</code></pre><h3 id="ps-process-status---顯示進程狀態的指令">ps (process status) - 顯示進程狀態的指令<a class="h-anchor" href="#ps-process-status---%e9%a1%af%e7%a4%ba%e9%80%b2%e7%a8%8b%e7%8b%80%e6%85%8b%e7%9a%84%e6%8c%87%e4%bb%a4" aria-label="這個段落的連結"></a></h3>
<ul>
<li>參數說明
<ul>
<li>a : 列出所有使用者與 terminal 無關的所有 process</li>
<li>u : 以使用者名稱顯示的格式</li>
<li>x : 列出與 terminal 有關的所有 process (通常與 a 搭配使用)</li>
</ul>
</li>
<li>顯示欄位 : USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND</li>
</ul>
<h3 id="kill---刪除執行中的-process">kill - 刪除執行中的 process<a class="h-anchor" href="#kill---%e5%88%aa%e9%99%a4%e5%9f%b7%e8%a1%8c%e4%b8%ad%e7%9a%84-process" aria-label="這個段落的連結"></a></h3>
<p>我們需要找到執行程式的 process PID 才能將其刪除 <code>(PID 就在 ps 進程狀態的第二欄)</code></p>
<h3 id="實際操作範例">實際操作範例<a class="h-anchor" href="#%e5%af%a6%e9%9a%9b%e6%93%8d%e4%bd%9c%e7%af%84%e4%be%8b" aria-label="這個段落的連結"></a></h3>
<ol>
<li>
<p>找出正在運行的排程</p>
<pre tabindex="0"><code>ps aux | grep cron.js
</code></pre><blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-01.webp" width="1024" height="112" alt="實際操作範例（圖 1）" fetchpriority="high" decoding="async"></p>
</blockquote>
</li>
<li>
<p>你可以看到執行排程的 PID 是 23888，把他複製起來用 kill 指令刪除</p>
<pre tabindex="0"><code>kill 23888
</code></pre><p>刪除後查詢進程，確認是否刪除成功</p>
<pre tabindex="0"><code>ps aux | grep cron.js
</code></pre><blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-02.webp" width="1024" height="87" alt="實際操作範例（圖 2）" loading="lazy" decoding="async"></p>
</blockquote>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="2-使用套件-forever-來管理排程">2. 使用套件 <code>forever</code> 來管理排程<a class="h-anchor" href="#2-%e4%bd%bf%e7%94%a8%e5%a5%97%e4%bb%b6-forever-%e4%be%86%e7%ae%a1%e7%90%86%e6%8e%92%e7%a8%8b" aria-label="這個段落的連結"></a></h2>
<p>單純使用 cron 套件會讓你遇到開頭所說的各種問題，所以遇到過這個問題的高手們也寫了一個<code>讓 Node.js 程式運行永不停止的套件：forever</code>，這個套件操作極其簡單，不僅能讓排程在背景穩定執行，還能在終端機的任何位置做管理</p>
<ul>
<li>
<p>首先要請你<mark>全域安裝</mark>這個套件，這樣才能在任何一個位置執行它</p>
<pre tabindex="0"><code>[sudo] npm install forever -g
</code></pre></li>
<li>
<p>基礎指令（以操作專案的 cron.js 為範例）</p>
<ul>
<li>
<p><strong>啟動程式</strong></p>
<pre tabindex="0"><code>forever --minUptime=1000 --spinSleepTime=1000 start tools/cron.js
</code></pre><blockquote>
<p>如果你沒加上 <code>--minUptime=1000 --spinSleepTime=1000</code> 的參數 會有警告如下圖</p>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-03.webp" width="1024" height="89" alt="2. 使用套件 forever 來管理排程（圖 3）" loading="lazy" decoding="async"></p>
</blockquote>
</li>
<li>
<p><strong>監聽檔案更動並自動重啟</strong></p>
<pre tabindex="0"><code>forever --minUptime=1000 --spinSleepTime=1000 -w start tools/cron.js
</code></pre><blockquote>
<ul>
<li>
<p>這個指令可以<mark>監控檔案的變更</mark>，解決過去爬蟲json資料變更但是執行時跑舊資料的問題</p>
</li>
<li>
<p>要在專案資料夾下<mark>新增 .foreverignore 的檔案</mark>，被列入的檔案/資料夾在偵測變更時會被忽略</p>
<h3 id="foreverignore">.foreverignore<a class="h-anchor" href="#foreverignore" aria-label="這個段落的連結"></a></h3>
<pre tabindex="0"><code>node_modules
.env
chromedriver.exe
debug.log
</code></pre></li>
</ul>
</blockquote>
</li>
<li>
<p><strong>顯示所有運行的狀態</strong></p>
<pre tabindex="0"><code>forever list
</code></pre><blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-04.webp" width="1024" height="85" alt=".foreverignore（圖 4）" loading="lazy" decoding="async"></p>
<ul>
<li>可以在 <code>logfile</code> 裡面看到排程執行的狀況</li>
</ul>
</blockquote>
</li>
<li>
<p><strong>關閉所有運行的程式</strong></p>
<pre tabindex="0"><code>forever stopall
</code></pre><blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-05.webp" width="1024" height="75" alt=".foreverignore（圖 5）" loading="lazy" decoding="async"></p>
</blockquote>
</li>
<li>
<p><strong>重新啟動程式</strong></p>
<pre tabindex="0"><code>forever restart tools/cron.js
</code></pre><blockquote>
<ul>
<li>請注意如果你 <mark>修改了 .env 裡面的資料，則必須要重啟才會生效</mark></li>
</ul>
</blockquote>
</li>
</ul>
</li>
<li>
<p>執行 forever 時你可能會遇到警告如下</p>
<pre tabindex="0"><code>(node:30512) Warning: Accessing non-existent property &#39;padLevels&#39; of module exports inside circular dependency
</code></pre><ul>
<li>這個警告是因為 forever 有相依套件在 node v14 之後不再支援，<mark>但這些警告不影響套件運行</mark></li>
<li>Node.js 的版本更新的非常快速，許多套件都可能在更新後不支援，<strong>所以更新版本後請切記要運行一次確保正常</strong></li>
<li>目前 <code>Node.js 的 LTS 版本為 12.19.0，如果你使用這個穩定的版本就能避免這個問題</code></li>
</ul>
</li>
</ul>
<hr>
<h2 class="h-nomark" id="3-在-packagejson-中加入驅動-forever-的-scripts">3. 在 package.json 中加入驅動 forever 的 scripts<a class="h-anchor" href="#3-%e5%9c%a8-packagejson-%e4%b8%ad%e5%8a%a0%e5%85%a5%e9%a9%85%e5%8b%95-forever-%e7%9a%84-scripts" aria-label="這個段落的連結"></a></h2>
<p>將昨天 cron 的 scripts 改為 forever 的版本</p>
<ul>
<li>為了避免重複啟動，這個 scipts 的執行邏輯為：<mark>先暫停所有運行的 forever 程式，然後再啟動程式</mark></li>
</ul>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#a5d6ff">&#34;forever&#34;</span><span style="color:#f85149">:</span><span style="color:#a5d6ff">&#34;forever stopall &amp;&amp; forever --minUptime=1000 --spinSleepTime=1000 -w start tools/cron.js&#34;</span>
</span></span></code></pre></div><hr>
<h3 id="執行程式">執行程式<a class="h-anchor" href="#%e5%9f%b7%e8%a1%8c%e7%a8%8b%e5%bc%8f" aria-label="這個段落的連結"></a></h3>
<ol>
<li>
<p>在專案資料夾的終端機(Terminal)執行指令啟動排程</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>yarn forever
</span></span></code></pre></div><blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-06.webp" width="1024" height="145" alt="執行程式（圖 6）" loading="lazy" decoding="async"></p>
</blockquote>
</li>
<li>
<p>然後再執行指令 <strong>forever list</strong> 確認排程正在背景運行</p>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-07.webp" width="1024" height="67" alt="執行程式（圖 7）" loading="lazy" decoding="async"></p>
</li>
</ol>
<hr>
<h3 id="ℹ-專案原始碼">ℹ️ 專案原始碼<a class="h-anchor" href="#%e2%84%b9-%e5%b0%88%e6%a1%88%e5%8e%9f%e5%a7%8b%e7%a2%bc" aria-label="這個段落的連結"></a></h3>
<ul>
<li>今天的完整程式碼可以在<a href="https://github.com/dean9703111/ithelp_30days/tree/master/day25">這裡</a>找到喔</li>
<li>我也貼心地把昨天的把昨天的程式碼打包成<a href="https://github.com/dean9703111/ithelp_30days/raw/master/sampleCode/day24_sample_code.zip">壓縮檔</a>，你可以在乾淨的環境嘗試用forever來控管排程吧
<ul>
<li>請記得在終端機下指令 <strong>yarn</strong> 才會把之前的套件安裝</li>
<li>windows需下載與你chrome版本相同的<a href="http://chromedriver.storage.googleapis.com/index.html">chrome driver</a>放在專案根目錄</li>
<li>要在tools/google_sheets資料夾放上自己的憑證，申請流程請參考<a href="https://deanlin.net/blog/202010/fb-ig-crawler-day-17/">Day17</a></li>
<li>調整fanspages資料夾內目標爬蟲的粉專網址</li>
<li>調整.env檔
<ul>
<li>填上FB登入資訊</li>
<li>填上FB版本(classic/new)</li>
<li>填上IG登入資訊</li>
<li>填上SPREADSHEET_ID</li>
<li>填上爬蟲執行時間(CRONJOB_TIME)</li>
</ul>
</li>
<li>在終端機下指令 <strong>npm install forever -g</strong> ，讓你在終端機的任何位置都能管控排程</li>
</ul>
</li>
</ul>
<h3 id="參考資源">參考資源<a class="h-anchor" href="#%e5%8f%83%e8%80%83%e8%b3%87%e6%ba%90" aria-label="這個段落的連結"></a></h3>
<ol>
<li><a href="https://medium.com/mess-up/%E5%A6%82%E6%9E%9Cctrl-c%E6%B2%92%E6%B3%95%E7%B5%82%E6%AD%A2%E6%80%8E%E9%BA%BC%E8%BE%A6-5e720fd66e32">如果ctrl + c沒法終止怎麼辦?</a></li>
<li><a href="http://puremonkey2010.blogspot.com/2011/02/linux-linux-ps-l-ps-aux-ps-axjf.html">Linux 程序管理 ( ps -l / ps aux / ps axjf )</a></li>
<li><a href="https://andy6804tw.github.io/2018/01/17/api-forever/">[Node.js打造API] 使用forever運行API永遠不停止</a></li>
</ol>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202010/fb-ig-crawler-day-25/images/fb-ig-crawler-day-25-08.webp" width="1024" height="233" alt="參考資源（圖 8）" loading="lazy" decoding="async"></p>
<p><strong>在許多人的幫助下，本系列文章已出版成書，並添加了新的篇章與細節補充：</strong></p>
<ul>
<li>加入更多實務經驗，用完整的開發流程讓讀者了解專案每個階段要注意的事項</li>
<li>將爬蟲的步驟與技巧做更詳細的說明，讓讀者可以輕鬆入門</li>
<li>調整專案架構
<ul>
<li>優化爬蟲程式，以更廣的視角來擷取網頁資訊</li>
<li>增加資料驗證、錯誤通知等功能，讓爬蟲執行遇到問題時可以第一時間通知使用者</li>
<li>排程部分改用 node-schedule &amp; pm2 的組合，讓讀者可以輕鬆管理專案程序並獲得更精確的 log 資訊</li>
</ul>
</li>
</ul>
<p><strong>有興趣的朋友可以到天瓏書局選購，感謝大家的支持。</strong></p>
<p><strong>購書連結</strong>：<a href="https://www.tenlong.com.tw/products/9789864348008">https://www.tenlong.com.tw/products/9789864348008</a></p>
</blockquote>
]]></content:encoded>
    </item>
  </channel>
</rss>
