1

我很难为这个问题找到一个好的标题,所以我希望这很清楚。我目前正在我的一个网站上使用 TwitterOauth 模块来发布推文。虽然这可行,但我需要限制提交的推文数量;每小时只有一个

注意:我没有使用数据库的选项。这对于这个问题至关重要。

我已将其合并到处理实际发布到 Twitter API 的 PHP 文件中,如下所示:

# Save the timestamp, make sure lastSentTweet exists and is writeable
function saveTimestamp(){
    $myFile = "./lastSentTweet.inc";
    $fh = fopen($myFile, 'w');
    $stringData = '<?php function getLastTweetTimestamp() { return '.time().';}';
    fwrite($fh, $stringData);
    fclose($fh);
}

# Include the lastSentTweet time
include('./lastSentTweet.inc');

# Define the delay
define('TWEET_DELAY', 3600);

# Check for the last tweet
if (time() > getLastTweetTimestamp() + TWEET_DELAY) {
    // Posting to Twitter API here
} else {
    die("No.");
}

文件的(初始)内容lastSentTweet.inc(chmod 777):

<?php function getLastTweetTimestamp() { return 1344362207;}

问题是,虽然这行得通;它允许意外的双重提交;如果多个用户(并且运行此脚本的站点当前非常繁忙)触发此脚本,则恰好有 2 次提交(或更多,尽管尚未发生)到 Twitter 滑过,而不仅仅是 1。我的第一个想法是打开,写入和关闭文件的(虽然是一分钟)延迟,但我可能是错的。

有谁知道什么允许意外双重提交(以及如何解决这个问题)?

4

1 回答 1

1

你得到了比赛条件。在进行更改时,您需要对文件实施锁定,但您需要将读取(语句)和更新include包含在锁内;关键是确保没有其他人(例如另一个 HTTP 请求)正在使用该文件,同时您读取它的当前值,然后使用新的时间戳更新它。

这将是相当无效的。您还有其他选项可能在您的 PHP 安装中可用,这里有一些:

  1. 即使没有数据库服务器也可以使用数据库SQLite
  2. 您可以将时间戳存储在 APC 中,并apc_cas()在更新时用于检测上次存储的时间戳是否仍然是最新的。

更新

您的锁定工作流程需要是这样的:

  1. 获取您存储的时间戳的锁定。如果您正在处理文件,则需要打开文件以进行读取写入,并已调用flock()它。flock()如果另一个进程锁定了文件,它将挂起,并且只有在获得锁定后才会返回,此时其他尝试锁定文件的进程将挂起。
  2. 从已锁定的文件中读取存储的时间戳。
  3. 检查自存储的时间戳以来所需的时间是否已过。
    • 只有通过了,才发送推文并将当前时间戳保存到文件中;否则您不会触摸存储的时间戳。
  4. 释放锁(只需关闭文件就足够了)。

这将确保在您读取和测试时间戳之后但在您存储新时间戳之前没有其他进程会更新时间戳。

于 2012-08-07T20:57:02.227 回答