我在 laravel 5.2 中有一個遺留應用程式,我們使用佇列來處理作業。我們觀察到佇列有時會獲得太多的作業,這會導致重復作業被分派,因為先前的作業沒有完成處理,并且分派此類作業的 cron 再次運行并最終一遍又一遍地分派它們。
一個簡單的解決方案是使這些作業獨一無二,如果它是 laravel 8,這將是一個非常簡單的改變。但是,我們處于 laravel 5.2 領域,所以我必須自己實施獨特的作業。或者如果有人可以提出更好的選擇?
另外,如果您要自己實施獨特的作業,您會怎么做?我正在考慮的方法是:
將作業的唯一鍵添加到快取或資料庫表中(意味著獲得了鎖) 處理完作業后清除條目(釋放鎖) 在調度作業之前,檢查該鍵是否存在于快取中(鎖能達到或不能達到)
uj5u.com熱心網友回復:
基于評論下的討論和互聯網的更多幫助,我繼續進行以下操作:
- 為作業創建唯一 ID
- 使用唯一 id 獲取鎖并將其存盤在快取中
- 如果獲得了鎖,則調度作業
- 作業完成后,從快取中釋放鎖
可能不是最好的實作,但絕對符合我們的要求。
代碼:
在調度作業之前獲取鎖的常用輔助函式:
/**
* Acquires a lock but storing a key on the cache for the provided duration
* the `$jobInstance` must have a `jobId()` function that provides a unique id
* for the job used to prevent duplicacy
*
* @var Job $jobInstance a Job instance to acquire a lock for
* @var int $minutes number of minutes to hold the lock for (default: 1 day)
*
* @return bool
*/
function acquireLock($jobInstance, $minutes = 1440)
{
$lockAcquired = false;
try {
DB::beginTransaction();
/**
* If the job instance does not provide a `jobId` function do not
* attempt to acquire a lock for it
*/
$jobId = method_exists($jobInstance, 'jobId') ? $jobInstance->jobId() : null;
if (!is_null($jobId)) {
$isLockAvailable = is_null(Cache::get($jobId));
if ($isLockAvailable) {
Cache::put($jobId, true, $minutes);
$lockAcquired = true;
}
}
DB::commit();
} catch (\Throwable $th) {
DB::rollback();
Log::error("Unable to acquire lock");
Log::error($th);
}
return $lockAcquired;
}
/**
* Attempts to acquires a lock for the job and dispatches it
* if the lock was successfull acquired
*
* @var Job $jobInstance Job instance to dispatch
*
* @return void
*/
function dispatchWithLock($jobInstance)
{
$isLockAcquired = acquireLock($jobInstance);
if ($isLockAcquired) {
dispatch($jobInstance);
}
}
添加了一個監聽AppServiceProvider器來釋放鎖
Queue::after(function (JobProcessed $event) {
/**
* Check if the job has a `jobId` function and release the lock used to
* maintain job uniqueness
*/
$jobInstance = unserialize($event->data['data']['command']);
$jobId = method_exists($jobInstance, 'jobId')
? $jobInstance->jobId()
: null;
if (!is_null($jobId)) {
Cache::forget($jobId);
}
});
jobId為需要唯一的作業添加了一個功能
/**
* Get a unique id for the job to prevent duplicates
*
* @return str
*/
public function jobId()
{
return str_slug(get_class($this)) . $this->myModel->id;
}
最后使用輔助函式調度作業
dispatchWithLock(new myJob($this));
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/435704.html
