PHP处理多异步请求限流:WordPress自定义锁机制是否可靠?
你的锁机制会失效,原因及修正方案
为什么当前锁机制会失效
- 竞态条件导致锁被多进程同时抢占:你的代码里第一行
update_option('web_hook_locker', 'yes')不是原子操作。当多个Webhook请求并发到达时,所有进程都会同时读取到锁的初始值(比如no),然后同时将锁设为yes——相当于所有进程都认为自己拿到了锁,后续的等待循环完全起不到排队作用。 - 逻辑倒置:你的代码逻辑是先锁上,再等锁被解开才执行请求,但第一个进程锁上后,锁只会在它执行完请求后才会被设为
no。而在它等待的2秒内,其他进程进来也会重新锁上,最后所有进程都会等待2秒后几乎同时执行请求,完全达不到间隔2秒的要求。
符合需求的修正方案
你的核心需求是:不管前一个请求是否完成,两次请求的发送时间至少间隔2秒。不需要用锁,而是通过记录「上次请求的时间戳」,结合数据库原子操作来实现:
function web_hook_handler() { global $wpdb; $time_option = 'last_webhook_request_timestamp'; $current_time = time(); while (true) { // 获取上次请求的时间戳,默认0表示从未执行过 $last_request_time = get_option($time_option, 0); // 计算需要等待的时间(确保至少间隔2秒) $wait_seconds = max(0, 2 - ($current_time - $last_request_time)); if ($wait_seconds > 0) { sleep($wait_seconds); // 等待后更新当前时间 $current_time = time(); continue; } // 原子更新时间戳:只有当数据库中记录的时间还是$last_request_time时,才更新为当前时间 // 这一步能确保只有一个进程能成功抢占"执行权" $update_result = $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->options} SET option_value = %d WHERE option_name = %s AND option_value = %d", $current_time, $time_option, $last_request_time ) ); // 更新成功,说明我们抢到了执行权限,跳出循环 if ($update_result !== false && $update_result > 0) { wp_cache_delete($time_option, 'options'); break; } // 更新失败,说明有其他进程先一步更新了时间戳,稍等再重试 usleep(100000); // 等待100毫秒 } // -------------------------- // 这里执行你的GET请求和数据处理 // -------------------------- // 不需要再更新时间戳,前面已经完成原子更新 }
方案说明
- 原子操作避免竞态:直接用数据库的
UPDATE ... WHERE语句,确保只有一个进程能成功更新时间戳,从根本上避免多进程同时执行请求的问题。 - 严格保证间隔:每个进程进来先检查上次请求时间,不足2秒就等待剩余时间,确保两次请求的发送时间至少间隔2秒,完全符合你的需求(不需要等待前一个请求完成)。
- 兼容WordPress环境:用
$wpdb操作数据库,同时刷新WordPress的选项缓存,避免后续进程读取到旧的时间戳。
内容的提问来源于stack exchange,提问作者ECOMMERCE LEARNING
相关产品推荐
相关产品推荐

