如何設定一個定時任務?

Sun_翁航發表於2018-01-10

定時任務在開發中是非常常見的一個需求,定時檢測過期優惠券、定時重啟、重新整理快取、備份資料等等都可以用到定時任務。在 Linux 上一般都是通過 crontab 來實現一個定時任務,這個是基於作業系統的;當然在應用層面也是可以實現的,如使用 Swoole 的定時器,Laravel 框架的任務排程(本質上也是 crontab ), Quartz 分散式任務排程框架等等。但是基於應用層面的定時任務侷限性比較大,一般都是隻能使用特定的語言來開發;比如 Swoole 一般都只能用 PHP 來開發;而通過 crontab 命令,我們可以在固定的時間間隔執行指定的系統指令或 shell 指令碼,基本上就不限制於開發語言了。

定義方式

在 Linux 下定義一個定時任務有兩種方式,一個是直接修改 /etc/crontab 檔案,還有一個是通過 crontab -e 命令來編輯任務檔案。這兩種方式的區別如下:

  • 定義方式不同 直接修改 /etc/crontab 的話在定義的時候需要在 command 之前指定一個命令的執行使用者

  • 範圍不同 修改 /etc/crontab 只有 root 使用者能用,可以更加方便的給其他使用者設定計劃任務; crontab -e 這種所有使用者都可以使用,普通使用者也只能為自己設定計劃任務,然後會自動寫入/var/spool/cron/usename

  • 系統級任務與使用者級任務 系統級任務排程主要完成系統的一些維護操作,使用者級任務排程主要完成使用者自定義的一些任務,可以將使用者級任務排程放到系統級任務排程來完成(不建議這麼做),但是反過來卻不行;root 使用者的任務排程操作可以通過 crontab –uroot –e 來設定,也可以將排程任務直接寫入 /etc/crontab 檔案;需要注意的是,如果要定義一個定時重啟系統的任務,就必須將任務放到 /etc/crontab 檔案,即使在 root 使用者下建立一個定時重啟系統的任務也是無效的。

如何使用

命令格式

crontab 的命令格式很簡單,這個是定義任務的,而不是定義任務檔案(任務檔案就是定義實際的什麼時間節點以及執行什麼任務)

crontab [-u user] file crontab [-u user] [ -e | -l | -r ]
複製程式碼

簡單說一下引數的含義:

-u user:用來設定某個使用者的 crontab 服務
file:  file 是命令檔案的名字,指定一個檔案並且該檔案中寫好了各個定時任務, 然後 crontab 會讀取該檔案內容並且載入 crontab
-e:    編輯某個使用者的 crontab 檔案內容, 預設編輯當前使用者的 crontab 檔案
-l:    顯示某個使用者的 crontab 檔案內容,預設顯示當前使用者的 crontab 檔案內容
-r:    從 /var/spool/cron 目錄中刪除某個使用者的 crontab 檔案,預設刪除當前使用者的 crontab 檔案
-i:    在刪除使用者的 crontab 檔案時給確認提示
複製程式碼

crontab 的檔案格式

以上是使用 crontab 命令時的引數以及含義,這個檔案格式才是真正定義時間和任務的。格式如下:

*  *  *  *  *  *
複製程式碼

具體含義是:

第 1 列分鐘 0~59
第 2 列小時 0~23(0表示子夜)
第 3 列日 1~31
第 4 列月 1~12
第 5 列星期 0~7(0和7表示星期天)
第 6 列要執行的命令
複製程式碼

可以看一張圖片來加深記憶:

在使用的時候可以直接通過 crontab -e 來開啟並且編輯當前的定時任務配置檔案, 然後可以通過 crontab -l 來列出 crontab 檔案內容.

常用例項

  1. 每1分鐘執行一次 command
* * * * * command
複製程式碼
  1. 每小時的第 3 和第 15 分鐘執行
3,15 * * * * command
複製程式碼

這個很有用, 特別是在定時抓取一些開彩資料就可以用到, 你懂的。

  1. 在上午 8 點到 11 點的第 3 和第 15 分鐘執行
3,15 8-11 * * * command
複製程式碼
  1. 每週一上午 8 點到 11 點的第 3 和第 15 分鐘執行
3,15 8-11 * * 1 command
複製程式碼
  1. 每晚的 21:30 重啟 smb
30 21 * * * /etc/init.d/smb restart
複製程式碼
  1. 每一小時重啟 smb
* */1 * * * /etc/init.d/smb restart
複製程式碼
  1. 晚上 11 點到早上 7 點之間,每隔一小時重啟 smb
0 23-7 * * * /etc/init.d/smb restart
複製程式碼

常見問題

環境變數問題

有時候建立了一個任務,但是這個任務卻無法自動執行,而手動執行這個任務卻沒有問題,這種情況一般是由於在 crontab 檔案中沒有配置環境變數引起的。 在 crontab 檔案中定義多個排程任務時,需要特別注環境變數的設定,因為我們手動執行某個任務時,是在當前 shell 環境下進行的,程式當然能找到環境變數,而系統自動執行任務排程時,是不會載入任何環境變數的,因此,就需要在 crontab 檔案中指定任務執行所需的所有環境變數。建議在定義任務的時候路徑都使用絕對 路徑。

執行時間

基本上 crontab 的最低檢測時間單位是分鐘,所以會每分鐘讀取一次 /etc/crontab/var/spool/cron 中的資料內容;因此只要編輯完檔案並且儲存之後,crontab 時設定就會自動執行;當然如果重啟 crontab 則可以立即執行了。當 crontab 失效時,可以嘗試重啟:

/etc/init.d/crond restart
複製程式碼

或者檢視日誌看某個任務有沒有執行報錯:

tail -f /var/log/cron
複製程式碼

附上 Ubuntu 上的重啟命令:

$sudo /etc/init.d/cron start
$sudo /etc/init.d/cron stop
$sudo /etc/init.d/cron restart
複製程式碼

系統日誌

每條任務排程執行完畢,系統都會將任務輸出資訊通過電子郵件的形式傳送給當前系統使用者,這樣日積月累日誌資訊會非常大,可能會影響系統的正常執行;因此,將每條任務進行重定向處理非常重要,可以在定義任務的時候忽略日誌輸出:

0 */3 * * * /usr/local/apache2/apachectl restart >/dev/null 2>&1
複製程式碼

歡迎關我的個人公眾號:左手程式碼

如何設定一個定時任務?