我提供的服务可以自动向客户收取费用,以便在帐户达到特定阈值时续订其信用额度。它的工作方式与Mandrill相同。
代码级别,其工作方式如下:当用户进行查询时,应用会将其信用减少为1,然后检查当前信用== {自动续订金额}。如果是这种情况,则会将作业发送到队列服务以开始续订。
测试在这里至关重要,我检查何时保持EQUALS是自动续订的值,而不是当它是低或等时,因为在这种情况下,每次用户查询API时都会进行更新而第一次自动续订尚未完全处理。
但我今天有一个奇怪的问题。我的一个客户有两个续订而不是一个。我的第一个猜测是API上存在竞争条件,这意味着两个请求同时进行,其中"剩余的"信用额度相同,等于自动续订的数量,从而投入两次自动续订。
我的问题很简单:如何避免再续约?
主要思想是解决竞争条件问题,但我不知道如何使用NGinx用PHP编写API。服务器应该知道对同一个帐户有N个请求,以便计算信用的当前使用情况(剩余 - {并发请求}),这似乎是不可能的。
我该怎么做?
答案 0 :(得分:2)
解决方案是只允许1个PHP进程在任何给定时间运行自动充电功能。最简单的方法是使用$('.myform').submit(function(e) {
var $this = $(this);
$.ajax({
type: "GET", // GET & url for json slightly different
url: "http://XXXXXXXX.list-manage2.com/subscribe/post-json?c=?",
data: $this.serialize(),
dataType : 'json',
contentType: "application/json; charset=utf-8",
error : function(err) { alert("Could not connect to the registration server."); },
success : function(data) {
if (data.result != "success") {
// Something went wrong, parse data.msg string and display message
} else {
// It worked, so hide form and display thank-you message.
}
}
});
return false;
});
:
flock()/fclose()
这将确保一次只运行一个PHP进程$lock = fopen("/tmp/renew", "w+");
flock($lock, LOCK_EX);
<renew code>
fclose($lock);
。因此,即使有100个续订请求,请求#1将运行续订代码,请求#2-#100将在<renew code>
时停止运行。当#1结束时,#2将运行,#2结束,#3运行,依此类推。
答案 1 :(得分:1)
我终于找到了这个解决方案:
由于从排队系统(Beanstalk)调用续订脚本,并且由于我的服务器只运行此续订脚本的一个实例,因此如果需要续订信用,我会再次检查续订脚本。
假设有两个同一个帐户的调用,第一个将返回比auto_renew数量少的信用,从而添加新的信用。 第二轮将看到现在有更多的信用额度而不是auto_renew数量,并且将被忽略。
我认为我已经解决了这个问题,但我更倾向于向@Brian提出一个明智的方法,以防万一脚本没有从排队系统中调用!