應(yīng)用場景
整個(gè) OpenResty 啟動(dòng)后,我們有時(shí)候需要后臺(tái)處理某些動(dòng)作,比如數(shù)據(jù)定期清理、同步數(shù)據(jù)等。而這個(gè)后臺(tái)任務(wù)實(shí)例我們期望是唯一并且安全,這里的安全指的是所有 Nginx worker 任意 crash 任何一個(gè),有機(jī)制合理保證后續(xù) timer 依然可以正常工作。
這里需要給大家介紹一個(gè)重要 API ngx.worker.id()。
語法: seq_id = ngx.worker.id()
返回當(dāng)前 Nginx 工作進(jìn)程的一個(gè)順序數(shù)字(從 0 開始)。
所以,如果工作進(jìn)程總數(shù)是 N,那么該方法將返回 0 和 N - 1 (包含)的一個(gè)數(shù)字。
該方法只對 Nginx 1.9.1+ 版本返回有意義的值。更早版本的 nginx,將總是返回 nil 。
解決辦法
通過 API 描述可以看到,我們可以用它來確定這個(gè) worker 的內(nèi)部身份,并且這個(gè)身份是相對穩(wěn)定的。即使當(dāng)前 Nginx 進(jìn)程因?yàn)槟承┰?crash 了,新 fork 出來的 Nginx worker 是會(huì)繼承這個(gè) worker id 的。
剩下的問題就比較簡單了,完全可以把我們的 timer 綁定到某個(gè)特定的 worker 上即可。 下面的例子,演示如何只在 worker.id 為 0 的進(jìn)程上運(yùn)行后臺(tái) timer。
init_worker_by_lua_block {
local delay = 3 -- in seconds
local new_timer = ngx.timer.at
local log = ngx.log
local ERR = ngx.ERR
local check
check = function(premature)
if not premature then
-- do the health check or other routine work
local ok, err = new_timer(delay, check)
if not ok then
log(ERR, "failed to create timer: ", err)
return
end
end
end
if 0 == ngx.worker.id() then
local ok, err = new_timer(delay, check)
if not ok then
log(ERR, "failed to create timer: ", err)
return
end
end
}