天天看點

php think crontab,crontab 定時任務在 ThinkPHP 内使用時的問題

摘要

咱們項目架構是 ThinkPHP5.0.24 ,系統環境為 Linux(Red Hat 4.8.5-11) 。

由于一些緣由,每次到月初,項目應用總會報錯:php

error_log(runtime/log/201903/20_sql.log): failed to open stream: Permission deniedhtml

記錄一下,解決的過程和方法。linux

心路曆程

round 1

根據報錯資訊能夠知道,有多是檔案夾的權限問題。

解決方法是: 經過指令行或者圖形化工具授予該日志檔案夾 777 的權限 。web

若是問題就這麼解決了,就不會有這篇文章了。sql

round 2

這個月處理完以後,下個月一樣會出現這個問題。shell

這就引發重視了呀。否則,難道每月都要調鬧鐘、手動受權新增的檔案夾寫入的權限嗎?vim

這不行。bash

欸!新增檔案夾?伺服器

為何新增的檔案夾會權限不足呢?架構

檢視各級日志檔案夾資訊:

> ll runtime/log/201903/

total 588

-rw-r--r-- 1 root root 370701 Mar 20 23:24 20.log

-rw-r--r-- 1 root root 217029 Mar 20 21:52 20_sql.log

-rw-r--r-- 1 root root 1192016 Mar 21 15:03 21_cli.log

此時檔案夾内隻能生成所屬 root 的檔案。

> ll runtime/log/

total 4

drwxr-xr-x 2 root root 4096 Mar 20 17:55 201903 // 此時報錯,error 日志無權限寫入

// 改為 drwxrwxrwx 2 root root 4096 Mar 20 17:55 201903 可解決,可是下月問題重制

// 删除此檔案夾,主動請求接口生成:drwxr-xr-x 2 www www 4096 Mar 20 17:55 201903 可順利寫入

通過删除檔案夾「runtime/log/201903/」,跑接口測試從新生成檔案夾發現,此時生成的檔案夾所屬組和所屬使用者是 www 。

那麼說明,出問題的這個檔案夾(所屬 root)不是跑架構的接口記錄日志時生成的。

那麼這個 root 所屬的檔案夾是誰生成的呢?

觀察成功生成的日志檔案可發現有以 _cli.log 結尾的檔案。這不是定時任務的日志檔案嗎?隻有它能正常運作?

緣由是:以 root 權限設定的 crontab 裡每分鐘執行的計劃任務,在每月初第一時間執行并在架構下建立了 _cli.log 類型的日志。是以該月的檔案夾所屬就為 root ,而使用者 www 在此檔案夾内預設沒有寫入的權限,進而緻使的報錯。

round 3

既然知道了是 crontab 的定時任務的問題,那就重點盤它吧。

在進一步了解 crontab 的知識root 下能夠設定指定使用者(好比個人 www 使用者)的時程表。原文以下:

-u user 是指設定指定 user 的時程表,這個前提是你必需要有其權限(好比說是 root)才可以指定他人的時程表。若是不使用 -u user 的話,就是表示設定本身的時程表。

經過如下操做:

> crontab -e -u www

把原來每分鐘執行架構腳本的定時任務所有搬到了這個隻針對 www 使用者的時程表裡。這樣第一時間生成的檔案夾「runtime/log/201903/」的所屬就是 www 了。

搬到以 www 使用者運作的時程表後,發現:

生成的日志檔案夾「runtime/log/201903/」的所屬使用者(組)确實變為了 www ,也沒有發生錯誤日志生成權限不足的問題(也就是上文說起的問題成功解決了,證明這個方向是可取的);

沒有生成 _cli.log 等定時任務運作産生的日志檔案,也就是說新的定時任務沒有執行成功。

round 4

排查為什麼定時任務沒有執行成功。

先排查系統日志

> tail -f /var/log/cron

Mar 21 10:18:01 localhost CROND[22349]: (www) CMD (「時程表中的 command」)

... (www) MAIL (mailed 58 bytes of output but got status 0x004b#012)

注意到上面的 MAIL 的資訊,查了一下:

這個實際上是 postfix 的配置問題,本次的問題不在這,是計劃任務在執行完以後會經過 postfix 發郵件給執行完的使用者郵箱,如今發不出去緻使的,修改下配置就好了。

修改配置:

> vim /etc/postfix/main.cf

inet_interfaces = all

inet_protocols = all

確定這兩個都是all 就能夠了,而後重新開機 postfix。

重新開機後确實沒有了那條關于 MAIL 的資訊,可是會有以下提醒:

You have new mail in /var/spool/mail/root

經過指令檢視:

> tail -f /var/spool/mail/root

X-Cron-Env:

X-Cron-Env:

X-Cron-Env:

X-Cron-Env:

X-Cron-Env:

Message-Id:

Date: Thu, 21 Mar 2019 10:17:01 +0800 (CST)

/bin/bash: ***.log: Permission denied

好了,Permission denied,也就是說時程表裡的任務後面的輸出日志權限不足咯。

由于時程表改為了指定使用者的了,是以權限不足也正常。

找到緣由了,那麼解決方案有兩個:

找到輸出日志的預設檔案夾,受權給 www 使用者寫入的權限;

删除輸出日志。

基于種種緣由想偷懶,好比時程表裡跑的是架構内的 php 檔案,會在架構内的日志檔案夾生成 _cli.log 或 _error_cli.log 的日志,是以就選擇了直接删掉了時程表中的輸出日志部分。

删除了輸出日志,可是若是報錯,依舊會發送 mail 到 /var/spool/mail/root ,此時能夠在指令後面加上 >/dev/null 2>&1 ,就不會發送 mail 了。

至此,定時任務恢複正常。

也就是 KO!

其它問題

1. 日志檔案生成的全部者為 root

經過指令:

> crontab -e

預設設定目前使用者的時程表。

若是以 root 使用者登入(果真要盡可能避免啊摔),設定的時程表就屬于 root 的了。

2. 關于 TP5 生成的錯誤日志是否報錯的問題

測試以下:

try {

Log::write('test', 'error');

//Log::error('test:');

} catch (\Exception $e) {

echo '抛出異常啦!';

}

一樣是無寫入 error 檔案的權限,Log::write 會抛出異常,中斷程式;而 Log::error 不會抛出異常,也不生成檔案。

總結

雖然解決了困惑已久的問題頗有成就感,可是歸根結底是由于使用了 root 登入管理伺服器緻使的問題。

流下了沒有技術的淚水啊。但願同道中人能避免踩坑吧。