我有一个 Sinatra 应用程序和 DRb 服务器对象配对。当我尝试将 Sinatra params 散列传递给我的服务器对象上的方法时,我得到 DRb::DRbConnError …DRb::DRbServerNotFound ,但是当我直接传递一个简单的散列时,同样的方法有效。

  • 为什么我在 Sinatra 参数散列中出现这个错误?
  • 解决此问题的最简单和最正确的解决方法是什么?

  • 这是一个简单的测试用例:

    # server.rb
    require 'drb'
    class Server; def echo( hash ); hash; end; end
    DRb.start_service 'druby://localhost:9007', Server.new
    DRb.thread.join
    

    # app.rb
    require 'sinatra'
    require 'drb'
    SERVER  = DRbObject.new_with_uri 'druby://localhost:9007'
    get("/params"){ SERVER.echo(params).inspect        }
    get("/hash"  ){ SERVER.echo(hello:'world').inspect }
    

    这两个都在自己的进程中运行:

    phrogz$ curl http://localhost:4567/hash
    {:hello=>"world"}
    
    phrogz$ curl http://localhost:4567/params
    DRb::DRbConnError - DRb::DRbServerNotFound:
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1653:in `current_server'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1721:in `to_id'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1050:in `initialize'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:642:in `new'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:642:in `make_proxy'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:559:in `rescue in dump'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:556:in `dump'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:603:in `block in send_request'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:602:in `each'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:602:in `send_request'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:903:in `send_request'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1196:in `send_message'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1088:in `block (2 levels) in method_missing'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1172:in `open'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1087:in `block in method_missing'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1105:in `with_friend'
     /usr/local/lib/ruby/1.9.1/drb/drb.rb:1086:in `method_missing'
     app.rb:4:in `block in <main>'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1152:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1152:in `block in compile!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:724:in `instance_eval'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:724:in `route_eval'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:708:in `block (2 levels) in route!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:758:in `block in process_route'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:755:in `catch'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:755:in `process_route'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:707:in `block in route!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:706:in `each'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:706:in `route!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:843:in `dispatch!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:644:in `block in call!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:808:in `instance_eval'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:808:in `block in invoke'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:808:in `catch'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:808:in `invoke'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:644:in `call!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:629:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/head.rb:9:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/commonlogger.rb:18:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/showexceptions.rb:21:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/methodoverride.rb:24:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1272:in `block in call'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1303:in `synchronize'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1272:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/content_length.rb:13:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/chunked.rb:15:in `call'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/connection.rb:84:in `block in pre_process'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/connection.rb:82:in `catch'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/connection.rb:82:in `pre_process'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/connection.rb:57:in `process'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/connection.rb:42:in `receive_data'
     /usr/local/lib/ruby/gems/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run_machine'
     /usr/local/lib/ruby/gems/1.9.1/gems/eventmachine-0.12.10/lib/eventmachine.rb:256:in `run'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/backends/base.rb:61:in `start'
     /usr/local/lib/ruby/gems/1.9.1/gems/thin-1.2.11/lib/thin/server.rb:159:in `start'
     /usr/local/lib/ruby/gems/1.9.1/gems/rack-1.2.2/lib/rack/handler/thin.rb:14:in `run'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/base.rb:1234:in `run!'
     /usr/local/lib/ruby/gems/1.9.1/gems/sinatra-1.2.6/lib/sinatra/main.rb:25:in `block in <module:Sinatra>'
    

    这是在 OS X 上的 Ruby 1.9.2 下运行的,并不是我认为它有什么不同。

    最佳答案

    简答

    你需要添加

    DRb.start_service
    
    app.rb 在您尝试进行远程调用之前。

    如果您有兴趣,请说明

    Sinatra params 散列是使用关联的块创建的,以处理引用缺失键 ( here's the source ) 的情况。这意味着有一个 Proc 对象与之关联。

    Drb 通过编码它们来回传递参数。但是,来自 the Marshal docs :



    因此,尝试通过网络传递这个 params 散列会出现问题,因为它包含一个不可编码的过程对象。

    现在到 the Drb docs :



    好消息,它应该仍然有效。那么怎么了?在 Drb 文档中,我们在示例代码中找到了这一点:
    # Start a local DRbServer to handle callbacks.
    #
    # Not necessary for this small example, but will be required
    # as soon as we pass a non-marshallable object as an argument
    # to a dRuby call.
    DRb.start_service
    

    因此,似乎正在发生的事情是 Drb 正在尝试获取过程对象的远程引用以传递给服务器,但由于没有设置客户端的 Drb 服务,因此无法实现。

    原答案

    (我将把它留在这里,它可能是我感兴趣的。这是我在弄清楚这一切的过程中的一个休息点。这也是一个可能的替代解决方案。有趣的是,我现在似乎是我提到的知识渊博的人到,至少在原因方面。)

    这是一个可能的解决方法。问题似乎在于使用块创建的哈希来处理丢失的键(即 Sinatra's params hash is ),因此您可以将哈希的内容提取到一个新的中。 params.cloneparams.merge({}) 似乎都保留了 proc(您可以使用 Hash#default_proc 进行检查),但是 {}.merge(params) (或 merge! )为您提供了一个与 Drb 一起使用的干净的哈希值。

    因此,在此示例中,请执行以下操作:
    get("/params"){ SERVER.echo({}.merge params).inspect
    

    为什么 Drb 会发生这种情况,而 proc 会发生这种情况,无论这是最简单还是最正确的解决方法,我都会留给知识渊博的人来解决。

    关于ruby - DRb::DRbServerNotFound 传递 Sinatra 参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6243729/

    10-13 03:57