将命令行应用程序移植到Sinatra / Ruby on Rails应用程序

时间:2014-11-17 00:43:20

标签: jquery ruby-on-rails ruby ajax sinatra

我有一个运行几分钟的Ruby命令行应用程序。在执行期间,在应用程序的每个阶段完成后,我会向命令行输出打印几条消息。

这只是为了让用户知道应用程序运行的阶段,并使应用程序提供更多信息。

现在,我想将应用程序移植到Sinatra应用程序。我已经准备好了整个框架。我正在使用jQuery AJAX将输出结果打印回用户。

问题是,它只在整个应用程序运行后呈现输出,因此使其不具有反应性(与命令行应用程序相比)。在某些情况下,整个应用程序运行甚至可能需要2-3分钟,然后将结果打印到网页上。

这相当于做一个POST,我在这里没有从jQuery AJAX调用中获得任何东西。 有没有办法可以将我打印到STDOUT的相同消息发送回网页上的用户。

这可能是一个非常简单的问题,但我是新手,并且在过去做过类似的事情。

如果您需要更多信息,请与我们联系。

3 个答案:

答案 0 :(得分:3)

你所说的是执行的状态。有几种方法可以解决它,使用服务器发送事件(SSE),使用websockets或只是轮询更改。

最简单的解决方案是轮询变更。有另一个Ajax方法每隔一段时间向网站发送一个请求,服务器将返回具有长时间运行进程当前状态的响应。

在长时间运行的过程中需要具备的是里程碑,您可以更新状态并且可以为其他人访问它,即某种数据库(Redis,Memcached,SQL-ish)或线程但是这不能很好地扩展。

答案 1 :(得分:2)

一段时间后我遇到了类似的问题,我采取了更聪明的问题。通过它的方式。我做的是,我添加了一个JavaScript代码片段,当ruby程序在后台运行时,它将继续在网页上加载新文本。 JavaScript代码将在完成该过程时停止运行。通过这种方式,您的应用程序将成为“响应式”#34;并会节省你很多时间。

执行上述操作的逐步方法应如下(据我所知):

  1. 在您的ruby代码中添加一个标志,当您的处理完成时,该标志应该转为true(取决于您的代码究竟是什么)。

  2. 添加一些javascript代码。像这样:

    $(document).ready(function() {
    
       $('#demo1').click(function() { 
    
      $.blockUI({ message: $('#loginForm') }); 
    
      setTimeout($.unblockUI, 2000); 
       });  
    });
    
    1. 要显示更改文字的动画,我添加了以下repository
    2. 中的代码

答案 2 :(得分:2)

我使用sinatra应用程序执行类似的操作,该应用程序运行我的规范并在浏览器中显示当前的构建状态。

有三件事情可以解决这个问题:

  1. 一个可以存储当前状态的全局对象(在我的例子中,包含Build列表的BuildQueue)
  2. 使用Thread.new
  3. 启动构建
  4. 使用IO.popen构建运行命令,因此我可以每行处理一行(将其置于构建日志数组中)
  5. 然后,我的javascript间隔函数向app传递构建id发出ajax请求,并返回logs数组(因此,不断扩充直到构建结束)。

    这是一个抽象的例子:

    require 'sinatra'
    require 'json'
    
    Thread.abort_on_exception = true
    
    Logs = []
    
    post '/build' do
      Logs.clear
      Thread.new do
        my_cmd = IO.popen( "my_long_running_binary 2>&1" )
        Logs.push( line ) while ( line = my_cmd.gets )
        my_cmd.close
      end
    
      200
    end
    
    get '/build.json' do
      JSON.dump Logs
    end