Ruby on rails 在Rails应用程序中异步执行存储过程
我在Rails中有一个应用程序,我试图做的是在用户从一个特定页面导航到另一个页面时异步执行一个数据库存储过程——用户必须在存储过程运行时继续导航 当过程完成时,我并不需要回调,我只需要在后台运行它 我正在尝试使用以下代码:Ruby on rails 在Rails应用程序中异步执行存储过程,ruby-on-rails,sidekiq,Ruby On Rails,Sidekiq,我在Rails中有一个应用程序,我试图做的是在用户从一个特定页面导航到另一个页面时异步执行一个数据库存储过程——用户必须在存储过程运行时继续导航 当过程完成时,我并不需要回调,我只需要在后台运行它 我正在尝试使用以下代码: require 'eventmachine' require 'em-http' require 'fiber' def async_fetch(url) f = Fiber.current http = EventMachine::HttpRequest.new(
require 'eventmachine'
require 'em-http'
require 'fiber'
def async_fetch(url)
f = Fiber.current
http = EventMachine::HttpRequest.new(url).get :timeout => 10
http.callback { f.resume(http) }
http.errback { f.resume(http) }
return Fiber.yield
end
EventMachine.run do
Fiber.new{
url = url_for :controller => 'common', :action => 'execute_stored_procedure'
data = async_fetch(url)
EventMachine.stop
}.resume
end
这里的问题是,当存储过程启动时,必须将用户重定向到另一个页面,但下一个页面仍处于“挂起”状态,并且只有在过程完成时才会呈现
我曾尝试使用thin(在我的开发环境中)作为我的服务器,并使用--threaded选项,但没有成功,现在我正在考虑在生产服务器中使用多线程模式的Phusion Passenger Enterprise,但这是一个商业版本,没有任何试用版,我担心这不是我需要的
有人知道实现这一目标的好办法吗?要执行存储过程,我必须向我的应用程序正在运行的同一个Web服务器发出请求,因此我的Web服务器必须一次接受多个连接(多线程),对吗
一些有用的信息:
- Ruby 1.9.3p385
- 轨道3.2.13
- SQL Server 2012
- Linux lucid32 2.6.32-45-generic#102 Ubuntu(流浪机器)
- 瘦Web服务器
- Linux debian 2.6.32-5-xen-amd64
- 阿帕奇/普西翁乘客
require 'celluloid/autostart'
class PropertyWorker
include Celluloid
def engage(args)
ActiveRecord::Base.execute_procedure("gaiainc.sp_ins_property_profiles", args[:id])
end
end
...
def create
@property = Property.new(params[:property])
respond_to do |format|
if @property.save
PropertyWorker.new.async.engage({:id => @property.id})
format.html { redirect_to new_enterprise_property_activation_url(@property.enterprise.id, @property.id) }
format.json { render json: @property, status: :created, location: @property }
else
format.html { render action: "new" }
format.json { render json: @property.errors, status: :unprocessable_entity }
end
end
end
然后调用操作“create”时,将创建记录,存储过程开始,但下一页未呈现,请求在浏览器中保持“挂起”,直到过程完成。该过程一完成,页面即被呈现
我不知道发生了什么事。该过程不应该在后台运行吗?如果您想从请求/响应线程运行异步的东西,这听起来像是什么,那么您应该使用后台处理系统来完成这项工作 有各种各样的宝石可以做到这一点-看看,作为一些更受欢迎的选择。它们通常需要一些备份存储(Redis、MongoDB、Rails数据库)来跟踪需要运行或当前正在运行的任务
或者,Unicorn可能适合您,因为它实际上产生了独立的进程,不会锁定GVL-但我认为底层系统不应该由您正在解决的问题类型决定。如果您想从请求/响应线程运行异步的东西,这听起来就是这样,然后,您应该使用后台处理系统来执行此操作 有各种各样的宝石可以做到这一点-看看,作为一些更受欢迎的选择。它们通常需要一些备份存储(Redis、MongoDB、Rails数据库)来跟踪需要运行或当前正在运行的任务
或者,Unicorn可能会为您工作,因为它实际上会产生单独的进程,不会锁定GVL-但我认为底层系统不应该由您所解决的问题类型决定。在类似的情况下,我建议使用或。您要做的是剥离一个线程并执行某些操作,返回对调用进程的访问并让它继续 Sidekiq需要一个单独的进程来运行(和Redis),赛璐珞则不需要。否则,它们是相似的 Sidekiq:
class AsyncProc
include Sidekiq::Worker
def perform(args)
CodeToExecuteStoredProcedure.engage! args
end
end
require 'celluloid/autostart'
class AsyncProc
include Celluloid
def engage(args)
CodeToExecuteStoredProcedure.engage! args
end
end
你可以这样称呼它:
AsyncProc.perform_async {whatever: arguments, you: want}
这将在Redis中安排一个作业,并在备用Sidekiq工作人员有时间时执行
赛璐珞:
class AsyncProc
include Sidekiq::Worker
def perform(args)
CodeToExecuteStoredProcedure.engage! args
end
end
require 'celluloid/autostart'
class AsyncProc
include Celluloid
def engage(args)
CodeToExecuteStoredProcedure.engage! args
end
end
并称之为:
AsyncProc.new.async.engage {whatever: arguments, you: want}
这将异步执行,几乎可以立即执行。在类似的情况下,我建议使用或。您要做的是剥离一个线程并执行某些操作,返回对调用进程的访问并让它继续 Sidekiq需要一个单独的进程来运行(和Redis),赛璐珞则不需要。否则,它们是相似的 Sidekiq:
class AsyncProc
include Sidekiq::Worker
def perform(args)
CodeToExecuteStoredProcedure.engage! args
end
end
require 'celluloid/autostart'
class AsyncProc
include Celluloid
def engage(args)
CodeToExecuteStoredProcedure.engage! args
end
end
你可以这样称呼它:
AsyncProc.perform_async {whatever: arguments, you: want}
这将在Redis中安排一个作业,并在备用Sidekiq工作人员有时间时执行
赛璐珞:
class AsyncProc
include Sidekiq::Worker
def perform(args)
CodeToExecuteStoredProcedure.engage! args
end
end
require 'celluloid/autostart'
class AsyncProc
include Celluloid
def engage(args)
CodeToExecuteStoredProcedure.engage! args
end
end
并称之为:
AsyncProc.new.async.engage {whatever: arguments, you: want}
这将异步执行,几乎可以立即执行。+1用于本例中的赛璐珞。管理事件、光纤和线程可能是一项困难的任务,利用一个预烘焙的框架来完成这项任务非常有意义。我创建了一个使用赛璐珞的小型rails应用程序。它会立即将控制权返回到浏览器。。。当
参与时,您是否会将您的PropertyWorker更改为只需睡觉代码>?我想可能是存储过程锁定了你的数据库。Jesse,我试着做一个简单的“睡眠”而不是执行这个过程,结果成功了!现在,我将查看该过程是否锁定了数据库,并将发布结果。非常感谢。我的存储过程现在使用'nolock'参数进行简单的选择,以确保它没有锁定数据库。在程序完成之前,我的请求仍处于挂起状态。我将尝试将应用程序部署到我的生产服务器上,以检查其行为。sidekiq的工作非常出色。非常感谢你的帮助,杰西+在这种情况下,赛璐珞为1。管理事件、光纤和线程可能是一项困难的任务,利用一个预烘焙的框架来完成这项任务非常有意义。我创建了一个使用赛璐珞的小型rails应用程序。它会立即将控制权返回到浏览器。。。当参与时,您是否会将您的PropertyWorker更改为只需睡觉代码>?我想可能是存储过程锁定了你的数据库。Jesse,我试着做一个简单的“睡眠”测试