Rails5+Mongoid6.4中线程阻塞主线程问题求助
解决Rails线程中访问Mongoid关联挂起的问题
核心问题原因
Mongoid 6.x的数据库连接是线程绑定的,新创建的线程默认没有初始化Mongoid的连接上下文;同时Rails 5.2的executor仅处理Active Record等Rails核心组件的上下文,不会自动初始化Mongoid的连接。直接访问延迟加载的关联(如s.emails)会导致线程阻塞,等待数据库连接但无法获取。
解决方案
1. 手动初始化Mongoid线程上下文
在线程内的executor上下文里,用Mongoid的with_session块包裹数据库操作,确保线程获得可用的数据库连接:
recalculate_archived_emails = Thread.new(company) do |c| execution_context = Rails.application.executor.run! # 包裹Mongoid数据库操作,初始化线程连接上下文 Mongoid::Clients.with_session do |session| stores = c.active_stores puts "all stores:" stores.each do |s| puts "#{s.name}" all_emails = s.emails.to_a # 显式加载避免延迟加载阻塞 # 耗时计算代码... end end ensure execution_context.complete! if execution_context end recalculate_archived_emails.join
2. 预加载关联避免延迟加载
在获取stores时预加载emails关联,彻底避免在线程内触发延迟加载:
recalculate_archived_emails = Thread.new(company) do |c| execution_context = Rails.application.executor.run! Mongoid::Clients.with_session do |session| # 预加载emails关联,减少线程内的数据库操作依赖 stores = c.active_stores.includes(:emails) puts "all stores:" stores.each do |s| puts "#{s.name}" all_emails = s.emails # 直接使用预加载的数据,无需再次查询 # 耗时计算代码... end end ensure execution_context.complete! if execution_context end recalculate_archived_emails.join
3. 检查MongoDB连接池配置
确保mongoid.yml中的连接池大小足够支撑线程并发,避免连接耗尽导致阻塞:
production: clients: default: uri: mongodb://localhost:27017/your_db options: pool_size: 10 # 根据线程数调整,确保大于并发线程数
内容的提问来源于stack exchange,提问作者MDickten
相关产品推荐
相关产品推荐

