尽可能跑

时间:2015-11-17 22:00:14

标签: ruby performance optimization sinatra

在我的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小于某个数字,那么它将运行任务利用负载增加。

2 个答案:

答案 0 :(得分:2)

正如安德鲁提到的那样(正确 - 不确定他为何被拒绝),Sinatra stops在看到redirect时处理路线,因此任何后续陈述都不会执行。正如您所说,您不希望将之前的那些语句放在 redirect之前,因为这会阻止请求直到它们完成。您可以在不使用redirect方法和然后调用MyClass#run的情况下将重定向状态和标头发送到客户端。这将产生预期的效果(从客户端的角度来看),但服务器进程(或线程)将阻塞直到它完成。这是不合需要的,因为该进程(或线程)在解除阻塞之前将无法提供任何新请求。

您可以派生一个新进程(或生成一个新线程),以便从与请求关联的主进程异步处理此后台任务。不幸的是,这种方法有可能变得混乱。您必须围绕不同的情况编写代码,例如后台任务失败,或fork / spawn失败,或者如果主要请求进程拥有正在运行的线程或其他进程,则不会结束。 (免责声明:我对Ruby和Rack中的IPC不太了解不同的应用程序服务器,以了解所有不同的场景,但我相信这里有龙。)

此类问题最常见的解决方案模式是将任务推送到某种工作队列中,以便稍后由另一个进程提供服务。将任务推送到队列理想情况下是一个非常快速的操作,并且不会阻止主进程超过几毫秒。这引入了一些新的挑战(队列在哪里?如何描述任务以便以后可以在没有任何上下文的情况下促进它?我们如何维护工作流程?)但幸运的是,很多腿部工作已经完成了由其他人完成。 :-)

delayed_job宝石,它似乎提供了一个很好的一体化解决方案。不幸的是,它主要面向Rails和ActiveRecord,而人们过去为使其与Sinatra一起工作所做的努力看起来没有得到维护。与框架无关的当代解决方案是ResqueSidekiq。使用任一选项启动并运行可能需要一些努力,但如果您在应用程序中有多个“可以运行时”类型的功能,那么这将是非常值得的。

答案 1 :(得分:0)

MyClass.run(temp)从未实际执行过。在您对/路径的当前请求中,您实例化MyClass的新实例,然后它会立即向get发出/home个请求。我不完全确定问题是什么。如果您希望在重定向后执行某些操作,则该功能需要存在于/home路由中。

get '/home' do
  # some code like MyClass.run(some_arg)
end