自动续订系统,如何避免多次续订?
Autorenew system, how to avoid multiple renew?
我提供一项服务,当我的客户的帐户达到特定阈值时,可以自动向他们收取续订信用额度的费用。它的工作方式与 Mandrill.
相同
代码层,其工作原理如下:当用户进行查询时,应用将其积分减为一,然后检查当前积分是否== {auto renew amount}。如果是这种情况,则会将作业发送到队列服务以开始更新。
这里的测试很关键,我检查剩余值何时等于自动更新的值,而不是当它低于或等于时,因为在这种情况下,每次用户查询时都会进行更新 API 而第一次自动续订还没有完全处理。
但是我今天遇到了一个奇怪的问题。我的一位客户有两个续订而不是一个。我的第一个猜测是 API 上存在竞争条件,这意味着同时发出两个请求,"remaining" 信用相同,并且等于自动更新的数量,因此抛出两个自动 -更新。
我的问题很简单:我怎样才能避免更新两次?
主要想法是解决竞争条件问题,但我不知道如何,API 是用 NGinx 写在 PHP 中的。服务器应该知道对同一个帐户发出了 N 个请求,以计算信用的当前使用情况(剩余 - {并发请求}),这似乎是不可能的。
我该怎么做?
一个解决方案是在任何给定时间只允许 1 个 PHP 进程来 运行 自动充电功能。最简单的方法是用 flock()/fclose()
:
包围您的代码
$lock = fopen("/tmp/renew", "w+");
flock($lock, LOCK_EX);
<renew code>
fclose($lock);
这将确保一次只有 1 个 PHP 进程 运行ning <renew code>
。因此,即使有 100 个更新请求进来,请求 #1 也会 运行 更新代码,而请求 #2-#100 会在点击 flock()
时停止 运行ning。当#1 完成时,#2 将运行,当#2 完成时,#3 将运行s,依此类推。
我终于想到了这个解决方案:
由于更新脚本是从排队系统 (Beanstalk) 调用的,并且由于我的服务器只有 运行 这个更新脚本的一个实例,所以我再次检查更新脚本是否需要信用更新了。
假设同一个账户有两个调用,第一个调用将比 auto_renew 数量少 return 个积分,从而增加新的积分。
第二个 运行 将看到现在的积分比 auto_renew 数量多,将被忽略。
我想我已经关闭了这个问题,但我更愿意把重点交给@Brian,他有一个聪明的方法来做到这一点,以防脚本不是从排队系统调用的!
我提供一项服务,当我的客户的帐户达到特定阈值时,可以自动向他们收取续订信用额度的费用。它的工作方式与 Mandrill.
相同代码层,其工作原理如下:当用户进行查询时,应用将其积分减为一,然后检查当前积分是否== {auto renew amount}。如果是这种情况,则会将作业发送到队列服务以开始更新。
这里的测试很关键,我检查剩余值何时等于自动更新的值,而不是当它低于或等于时,因为在这种情况下,每次用户查询时都会进行更新 API 而第一次自动续订还没有完全处理。
但是我今天遇到了一个奇怪的问题。我的一位客户有两个续订而不是一个。我的第一个猜测是 API 上存在竞争条件,这意味着同时发出两个请求,"remaining" 信用相同,并且等于自动更新的数量,因此抛出两个自动 -更新。
我的问题很简单:我怎样才能避免更新两次?
主要想法是解决竞争条件问题,但我不知道如何,API 是用 NGinx 写在 PHP 中的。服务器应该知道对同一个帐户发出了 N 个请求,以计算信用的当前使用情况(剩余 - {并发请求}),这似乎是不可能的。
我该怎么做?
一个解决方案是在任何给定时间只允许 1 个 PHP 进程来 运行 自动充电功能。最简单的方法是用 flock()/fclose()
:
$lock = fopen("/tmp/renew", "w+");
flock($lock, LOCK_EX);
<renew code>
fclose($lock);
这将确保一次只有 1 个 PHP 进程 运行ning <renew code>
。因此,即使有 100 个更新请求进来,请求 #1 也会 运行 更新代码,而请求 #2-#100 会在点击 flock()
时停止 运行ning。当#1 完成时,#2 将运行,当#2 完成时,#3 将运行s,依此类推。
我终于想到了这个解决方案:
由于更新脚本是从排队系统 (Beanstalk) 调用的,并且由于我的服务器只有 运行 这个更新脚本的一个实例,所以我再次检查更新脚本是否需要信用更新了。
假设同一个账户有两个调用,第一个调用将比 auto_renew 数量少 return 个积分,从而增加新的积分。 第二个 运行 将看到现在的积分比 auto_renew 数量多,将被忽略。
我想我已经关闭了这个问题,但我更愿意把重点交给@Brian,他有一个聪明的方法来做到这一点,以防脚本不是从排队系统调用的!