通常需要10-20秒响应的API调用(到另一个服务)存储在数据库中,
存储后,系统会立即尝试使用API向用户显示结果,但它可能会失败(并显示失败但我们会自动重试),因此还有一个Cron Job设置每隔30秒运行一次再次尝试(失败)查询.
如果API返回成功(无论是即时使用还是使用Cron Job),则标志在数据库中更改为成功,并且不会再次运行.
我的问题是当Instant CallAPI正在进行中时,Cron Job可能还会尝试另一个调用,因为它尚未标记为成功,
同样在极少数情况下,当前一个Cron Job正在进行时,下一个Cron Job可能会再次运行代码.
我尝试将In ProcessAPI调用存储在数据库表中,Status=1并在API调用成功时将其删除,或者如果失败则将状态设置为0,
if ($status === 0)
{
// Set Status to 1 in Database First (or die() if database update failed)
// Then Call The API
// If Failed Set Status to 0 so Cron Job can try again
// If Successful Change Flag to success and remove from queue
}
Run Code Online (Sandbox Code Playgroud)
但如果在同一时间发生
Instant Call和Cron Job Call发生怎么办?他们都检查状态是否为0,然后将状态设置为1并执行API调用...
我尝试过正确的方法来处理这个问题吗?
如果有很多电话(有时+ 500 /秒),我应该担心它们在确切的时间发生(我在上面的黄色报价中解释的问题)
在PHP方面是不是真的有一种简单的方法来处理这种情况?如果没有,专家们认为哪种方式更好?下面是一些方法,但没有一个足够详细,没有任何一个有任何Downvotes/Upvotes.
PS对数据库有很多更新/插入,我不认为锁定是一个有效的想法,我不确定其余的想法.
小智 15
这正是Semaphore创建的原因.
在php中,它可以通过以下方式使用:在PHP中使用信号量实际上非常简单.只有4个信号量函数:
sem_acquire() – Attempt to acquire control of a semaphore.
sem_get() – Creates (or gets if already present) a semaphore.
sem_release() – Releases the a semaphore if it is already acquired.
sem_remove() – Removes (deletes) a semaphore.
Run Code Online (Sandbox Code Playgroud)
那么它们如何一起工作呢?首先,调用sem_get()来获取信号量的标识符.之后,您的一个进程将调用sem_acquire()来尝试获取信号量.如果它当前不可用,sem_acquire()将阻塞,直到另一个进程释放信号量.获取信号量后,您可以访问您使用它控制的资源.完成资源后,调用sem_release()以便另一个进程可以获取信号量.完成所有操作后,您已确保所有进程都不再需要信号量,您可以调用sem_remove()来完全删除信号量.
您可以在本文中找到有关此内容的更多信息和示例.
我在脚本中所做的是(伪代码)
SCRIPT START
LOCK FILE 'MYPROCESSFILE.LOCK'
DO SOMETHING I WANT
UNLOCK FILE 'MYPROCESSFILE.LOCK'
SCRIPT END
Run Code Online (Sandbox Code Playgroud)
因此,如果文件被锁定,第二个(重复的)进程将不会运行(将锁定/暂停/等待),直到文件被原始进程解锁。
编辑更新了 WORKING PHP 代码
<?php
class Locker {
public $filename;
private $_lock;
public function __construct($filename) {
$this->filename = $filename;
}
/**
* locks relevant file
*/
public function lock() {
touch($this->filename);
$this->_lock = fopen($this->filename, 'r');
flock($this->_lock, LOCK_EX);
}
/**
* unlock above file
*/
public function unlock() {
flock($this->_lock, LOCK_UN);
}
}
$locker = new Locker('locker.lock');
echo "Waiting\n";
$locker->lock();
echo "Sleeping\n";
sleep(30);
echo "Done\n";
$locker->unlock();
?>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3778 次 |
| 最近记录: |