在我的sinatra网络应用程序中,我有一条路线:
get "/" do
temp = MyClass.new("hello",1)
redirect "/home"
end
MyClass
的位置:
class MyClass
@instancesArray = []
def initialize(string,id)
@string = string
@id = id
@instancesArray[id] = this
end
def run(id)
puts @instancesArray[id].string
end
end
在某些时候我想运行MyClass.run(1)
,但我不希望它立即执行,因为这会降低服务器对某些客户端的响应速度。我希望服务器等待运行MyClass.run(temp)
,直到有一段时间负载较轻。我怎么能告诉它等到空载/轻载,然后运行MyClass.run(temp)
?我能这样做吗?
附录
以下是我想要做的一些示例代码:
$var = 0
get "/" do
$var = $var+1 # each time a request is recieved, it incriments
end
之后我会有一个循环来计算请求/分钟(所以一分钟后它会将$var
重置为0,如果$var
小于某个数字,那么它将运行任务利用负载增加。
答案 0 :(得分:2)
正如安德鲁提到的那样(正确 - 不确定他为何被拒绝),Sinatra stops在看到redirect
时处理路线,因此任何后续陈述都不会执行。正如您所说,您不希望将之前的那些语句放在 redirect
之前,因为这会阻止请求直到它们完成。您可以在不使用redirect
方法和然后调用MyClass#run
的情况下将重定向状态和标头发送到客户端。这将产生预期的效果(从客户端的角度来看),但服务器进程(或线程)将阻塞直到它完成。这是不合需要的,因为该进程(或线程)在解除阻塞之前将无法提供任何新请求。
您可以派生一个新进程(或生成一个新线程),以便从与请求关联的主进程异步处理此后台任务。不幸的是,这种方法有可能变得混乱。您必须围绕不同的情况编写代码,例如后台任务失败,或fork
/ spawn
失败,或者如果主要请求进程拥有正在运行的线程或其他进程,则不会结束。 (免责声明:我对Ruby和Rack中的IPC不太了解不同的应用程序服务器,以了解所有不同的场景,但我相信这里有龙。)
此类问题最常见的解决方案模式是将任务推送到某种工作队列中,以便稍后由另一个进程提供服务。将任务推送到队列理想情况下是一个非常快速的操作,并且不会阻止主进程超过几毫秒。这引入了一些新的挑战(队列在哪里?如何描述任务以便以后可以在没有任何上下文的情况下促进它?我们如何维护工作流程?)但幸运的是,很多腿部工作已经完成了由其他人完成。 :-)
有delayed_job宝石,它似乎提供了一个很好的一体化解决方案。不幸的是,它主要面向Rails和ActiveRecord,而人们过去为使其与Sinatra一起工作所做的努力看起来没有得到维护。与框架无关的当代解决方案是Resque和Sidekiq。使用任一选项启动并运行可能需要一些努力,但如果您在应用程序中有多个“可以运行时”类型的功能,那么这将是非常值得的。
答案 1 :(得分:0)
MyClass.run(temp)
从未实际执行过。在您对/
路径的当前请求中,您实例化MyClass
的新实例,然后它会立即向get
发出/home
个请求。我不完全确定问题是什么。如果您希望在重定向后执行某些操作,则该功能需要存在于/home
路由中。
get '/home' do
# some code like MyClass.run(some_arg)
end