【问题标题】:PHP: How to check if session_start will block or make it time outPHP:如何检查 session_start 是否会阻塞或超时
【发布时间】:2019-03-07 12:18:03
【问题描述】:

在某些情况下,我想取消已打开会话的用户的呼叫。 我使用session_start 来确保登录用户一次只能执行一个请求并且工作正常。但是所有后续调用都会无限期地阻塞,直到所有之前的调用都通过,这在某些情况下会让人不满意,比如行为不端的用户。

通常我知道的所有阻塞调用都有一个超时参数。 start_session 有这样的东西吗?

或者有没有可以在拨打session_start之前可以拨打session_opened_by_other_script的电话?

【问题讨论】:

  • 我很想知道你是如何做到这一点的。总是渴望学习一些东西。那么你能告诉我们一些代码吗
  • 在尝试长时间运行的任务之前,您是否应该注意关闭其他地方的会话...?
  • @RiggsFolly PHP 的标准会话机制自己完成了这一切。 stackoverflow.com/q/13651195/476
  • @deceze 我希望对调用进行序列化。
  • @deceze Ahh 现在我明白 OP 在说什么了。 :) 傻我!

标签: php session


【解决方案1】:

目前我的解决方案是使用 exec 一个 shell 脚本检查会话文件是否已经被锁定。 不推荐不完全理解的人使用。

基本上,它会尝试使用flock 锁定会话文件以获取指定的超时值。如果它未能这样做,则存在 408 请求超时。 (或 429 请求过多,如果可用)

为此,您需要...

  1. 及时了解您的会话 ID
  2. 有基于文件的会话

请注意,这不是原子的。仍然可能发生多个请求最终在 session_start 中等待。但这应该是一个罕见的事件。大多数电话应该被正确取消,这是我的议程。

class Session {

    static public function openWhenClosed() {

        if (session_status() == PHP_SESSION_NONE) {

            $sessionId = session_id();
            if ($sessionId == null)
                $sessionId = $_COOKIE[session_name()];

            if ($sessionId != null) {
                $sessFile = session_save_path()."/sess_".$sessionId;

                if (file_exists($sessFile)) {
                    $timeout = 30; //How long to try to get hold of the session
                    $fd = 9; //File descriptor to use to try locking the session file.

                    /*
                    * This 'trick' is not atomic!!
                    * After exec returned and session_start() is called there is a time window
                    * where it can happen that other waiting calls get a successful lock and also
                    * proceed and get then blocked by session_start(). The longer the sleep value
                    * the less likely this is to happen. But also the longer the extra delay
                    * for the call
                    */
                    $sleep = "0.01"; //10ms

                    //Check if session file is already locked by trying to get a lock on it.
                    //If it is, try again for $timeout seconds every $sleep seconds
                    exec("
                                exec $fd>>$sessFile;
                                while [ \$SECONDS -lt $timeout ]; do
                                    flock -n $fd;
                                    if [ \$? -eq 0 ]; then exit 0; fi;
                                    sleep $sleep;
                                done;
                                exit 1;
                            ", $null, $timedOut);



                    if ($timedOut) {
                        http_response_code(408); //408: Request Timeout. Or even better 429 if your apache supports it

                        die("Request canceled because another request is still running");
                    }
                }
            }

            session_start();
        }
    }
}

其他想法:

  1. 使用flock -w <timeout> 很诱人,但这样的方式更多 排队等候电话将设法使用execstart_session 获得锁并最终阻塞 session_start
  2. 如果您使用浏览器对此进行测试,请注意大多数浏览器执行命令队列并重用有限数量的连接。因此,他们不会在其他人完成之前开始发送您的请求。如果您没有意识到这一点,这可能会导致看似奇怪的结果。您可以使用多个并行的wget 命令进行更可靠的测试。
  3. 我不建议为正常的浏览器请求激活此功能。正如 2) 中提到的,在大多数情况下,浏览器已经处理了这个问题。我仅使用它来保护我的 API 免受在发送下一个请求之前不等待答案的恶意实现。
  4. 在我的整体负载测试中,性能影响可以忽略不计。但我建议您自己使用microtime() 调用在您的环境中进行测试

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 1970-01-01
    • 2010-12-02
    • 2018-03-19
    • 2019-02-06
    • 2011-09-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    相关资源
    最近更新 更多