我有一个Sinatra应用程序和DRb服务器对象配对。当我尝试将Sinatra params
哈希传递给我的服务器对象上的方法时,我得到DRb::DRbConnError …
DRb::DRbServerNotFound
,但是当我直接传递一个简单的哈希时,同样的方法也可以。
这是一个简单的测试用例:
# 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下运行,而不是我觉得它有所作为。
答案 0 :(得分:4)
您需要添加
DRb.start_service
在尝试拨打远程电话之前,请到app.rb
。
使用关联块创建Sinatra params哈希,以处理引用缺失键时的情况(here's the source)。这意味着有一个Proc
对象与之关联。
Drb通过编组来回传递参数。但是,来自the Marshal docs:
无法转储某些对象:如果要转储的对象包括绑定,过程或方法对象,类IO实例或单例对象,则会引发TypeError。
因此,尝试通过线路传递此params哈希会有问题,因为它包含一个不可编组的过程对象。
现在进入the Drb docs:
但是,如果无法编组对象,则会传递或返回对其的dRuby引用。这将作为DRbObject实例在远程端出现。在远程代理上调用的所有方法都将转发到本地对象,如DRbObjects的讨论中所述。它的语义类似于普通的Ruby pass-by-reference。
好消息,它应该仍然有效。那有什么不对?在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服务设置客户端而无法进行。
(我会把它留在这里,这可能是我感兴趣的。这是我的旅程中的一个休息点。这也是一个可能的替代解决方案。有趣的是,它似乎我< / em>现在我提到的知识渊博的人,至少就其原因而言。)
这是一种可行的解决方法。问题似乎是使用块来创建哈希来处理丢失的密钥(Sinatra's params hash is),因此您可以将哈希的内容提取到新的哈希中。 params.clone
和params.merge({})
似乎都保留了proc(您可以使用Hash#default_proc
查看),但是{}.merge(params)
(或merge!
)会为您提供一个干净的哈希值与Drb合作。
因此,在此示例中,请执行以下操作:
get("/params"){ SERVER.echo({}.merge params).inspect
为什么这种情况发生在Drb和哈希与procs,以及这是最简单或最正确的解决方法,我会留给更有知识的人。