cron-service

 

開發動機

自己平常有開一台專門Run Web的EC2

主機上有設定一些cron job

像是每週更新一次Let's Encrypt憑證

還有每天備份一次DB

雖然時間到了它都會自己跑

但是有時候我們並不知道這些job跑完後到底有沒有成功

 

像是之前我就因為執行SSL更新的cron job忘記用root來設定

每次跑都因為不是root所以被擋掉 (但是我並不知道這個狀況)

直到90天後憑證到期

開網站才突然發現SSL過期

雖然也可以每次自己隔一段時間上EC2看系統log查看看cron job結果

但是這樣實在太麻煩而且一定會忘記

如果能夠在每次執行完後自動主動通知我

我就能提早發現有問題的job馬上處理

想一想乾脆自己來開發個cron-service

 

主要功能

  • 可以一次設定多個不同的cron job
  • 可依照每個job的需求選擇需要的通知類型(目前通知類型有EmailLine,接下來打算開發Slack的通知)

 

相依套件

  • cron: 主要使用在cron job設定
  • shelljs: 執行設定檔的shell command
  • moment: 顯示記錄系統時間
  • axios: 用於發送第三方通知API
  • nodemailer: 用於發送Email通知

 

主要架構

在我的Repo的src/Modules資料夾中可以看出

整個service主要由兩支js負責

 

Runner.js

執行job要做的每個command

並且要確保每個command的順序

因此要使用ES7的async/await來處理

 

Notify.js

管理各種通知的Driver(目前有Email、Line)

並且依照各job的通知設定來使用指定的Driver做通知

我把所有實做通知的事情抽成Driver主要是為了提高維護性擴充性

各個Driver只要負責接收執行完的結果

然後專心實做好自己該通知的工作就好

其他的調度就由Notify.js來做

 

我的真實使用情境

我的主機使用情境目前的兩個job需要跑

  1. 每週一早上11點清除一些服務的log
  2. 每週一凌晨12點更新SSL憑證
  3. 每天早上10點查看pm2狀態(我用PM2來跑SSR,我很怕它掛掉)

 

我的cron-service設定檔

{
  "jobs": {
    "cleanCache": {
      "name": "清除Cache(每星期一早上11點)",
      "runAtStart": false,
      "schedule": "0 0 11 * * 1",
      "commands": [
        {
          "command": "php artisan cache:clear",
          "description": "清除blog cache",
          "cwd": "/blog/path"
        },
        {
          "command": "find /home/ubuntu/app/service/ -type f -name 'laravel.log' -delete",
          "description": "刪除所有laravel.log"
        },
        {
          "command": "pm2 flush",
          "description": "清除pm2 log"
        },
        {
          "command": "npm run cache:clean",
          "description": "清除SSR Server Cache",
          "cwd": "/home/ubuntu/app/service/puppeteer-server-side-render/Prod/Server"
        }
      ],
      "notify": ["line", "email"]
    },
    "renewSslCredentials": {
      "name": "更新Let's encrypt憑證(每星期一凌晨12點)",
      "runAtStart": false,
      "schedule": "0 0 0 * * 1",
      "commands": [
        {
          "command": "echo $USER",
          "description": "顯示使用者"
        },
        {
          "command": "./certbot-auto renew --no-self-upgrade",
          "description": "更新憑證",
          "cwd": "/home/ubuntu"
        }
      ],
      "notify": ["line", "email"]
    },
    "showPm2Status": {
      "name": "顯示pm2狀態(每天早上10點)",
      "runAtStart": false,
      "schedule": "0 0 10 * * *",
      "commands": [
        {
          "command": "pm2 status",
          "description": "pm2 status"
        }
      ],
      "notify": ["line", "email"]
    }
  },
  "notifyDrivers": {
    "line": {
      "token": "lineApiToken"
    },
    "email": {
      "transporter": {
        "port": 587,
        "host": "smtp.gmail.com",
        "username": "foo@bar.com",
        "password": "password"
      },
      "send": {
        "from": "foo@bar.com",
        "to": "target1@foobar.com,target2@foobar.com"
      }
    }
  }
}

 

Line通知

 

 

Email通知

 

 

 

 

其他想說的

 

使用感想

終於可以放心的把機器丟給cron自己處理

只要每天等通知看結果就好了

 

開發Line Notify Driver的原因

這個service會開發line原因主要是台灣目前用line的次數、頻率、時間實在太高

比Email高太多

所以用Line真的比較會看

不過像是上方那種PM2的狀態因為是用表格呈現

所以主要還是要靠Email來看比較好看

 

Line Notify的限制

我在開發的時候有發現

如果訊息太長太多的話

Line Notify的API會拒絕

所以如果使用的job會噴很多log出來

建議不要使用line來通知

不過我覺得Line通知也有他的好處

如果是頻率高(例如每半天、甚至是每小時)的小通知

我就不會想用Email (光想到塞爆信箱要刪就很煩)

這時後用Line就會很適合

 

安裝/使用方式

請詳見我的Repo