Puma如何获取当前运行中而非队列内的活跃请求,是否可手动开发?
Puma活跃请求查询需求解答
核心结论
该需求完全可实现,也支持手动开发对应功能。
Puma本身的运行时架构就将「正在被线程处理的活跃请求」和「等待队列中的待处理请求」分开存储:等待队列的请求存放在socket backlog或Puma内部的待处理队列中,还没有被分配到工作线程;活跃请求会绑定到对应工作线程的上下文,可直接读取。
手动开发实现思路
以下是符合你给出的示例场景的实现方案:
- 首先在Web应用中添加全局请求钩子,请求进入工作线程时将请求路径等信息写入线程本地存储,请求结束后清理存储避免内存泄漏
- 新增
/active_requests路由接口,接口逻辑中读取当前Puma实例的工作线程池,遍历所有忙碌线程,取出线程本地存储中记录的请求路径 - 过滤掉
/active_requests自身的请求(可根据需求调整是否包含),将收集到的路径返回即可,该逻辑完全不会读取到等待队列中的请求
简化代码示例(以Sinatra应用为例)
# 全局前置钩子:请求进入时存储路径到当前线程 before do Thread.current[:active_request_path] = request.path_info end # 全局后置钩子:请求结束后清理存储 after do Thread.current[:active_request_path] = nil end # 活跃请求查询接口 get '/active_requests' do return "服务未运行在Puma上" unless defined?(Puma::Server) && Puma::Server.current active_requests = [] # 遍历当前worker的所有忙碌线程,收集活跃请求路径 Puma::Server.current.thread_pool.busy_threads.each do |t| path = t[:active_request_path] next if path.nil? || path == '/active_requests' active_requests << path end active_requests.uniq.join("\n") end
场景匹配验证
你给出的1 worker / 1 thread配置的场景下,上述代码的运行结果和预期完全一致:
- 先请求
/test1,唯一的工作线程被占用,存储的路径为/test1,调用/active_requests返回/test1- 再请求
/test2,因无空闲线程,/test2被放入等待队列,未分配到工作线程,调用/active_requests仍返回/test1/test1处理完成返回200,线程被释放,/test2被分配到该线程处理,线程存储更新为/test2,调用/active_requests返回/test2
多worker模式适配说明
如果是多worker部署,上述单进程内的实现只能拿到当前请求命中的worker的活跃请求,要拉取全量数据可在Puma配置文件中开启状态存储:
- 在
puma.rb中添加配置:state_path 'tmp/puma.state' - 接口中通过
Puma::StateFile.new('tmp/puma.state').server拿到全局Puma实例,遍历所有worker的线程池即可收集全量活跃请求
内容的提问来源于stack exchange,提问作者gayavat
相关产品推荐
相关产品推荐

