DRb :: DRbServerNotНайдено прохождение параметров Синатры - PullRequest
3 голосов
/ 05 июня 2011

У меня есть приложение Sinatra и объект сервера DRb в паре.Когда я пытаюсь передать хэш Sinatra params методу на моем объекте сервера, я получаю DRb::DRbConnError … DRb::DRbServerNotFound, но тот же метод работает, когда я передаю простой хеш напрямую.

  1. Почему я получаю эту ошибку с хэшем параметров Sinatra?
  2. Какие самые простые и правильные обходные пути для решения этой проблемы?

Вотпростой тестовый пример:

# 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>'

Это работает под Ruby 1.9.2 на OS X, не такЯ думаю, что это имеет значение.

1 Ответ

4 голосов
/ 05 июня 2011

Короткий ответ

Вам необходимо добавить

DRb.start_service

к app.rb, прежде чем пытаться сделать удаленный вызов.

Объяснение, если вы заинтересованы

Хэш Sinatra params создается со связанным блоком для обработки случая, когда ссылаются на отсутствующие ключи ( вот источник ).Это означает, что с ним связан объект Proc.

Drb передает аргументы взад и вперед, сортируя их.Однако из Документы маршала :

Некоторые объекты не могут быть выгружены: если объекты, которые должны быть выгружены, включают в себя привязки, объекты процедур или методов, экземпляры класса IO или одиночные объектыбудет возникать ошибка TypeError.

Поэтому возникнут проблемы при попытке передать этот хэш параметров по проводам, поскольку он содержит недопустимый объект процедуры.

Теперь на Документация Drb :

Однако, если объект нельзя маршалировать, вместо него передается или возвращается ссылка dRuby на него.Это появится на удаленном конце как экземпляр DRbObject.Все методы, вызываемые на этом удаленном прокси, передаются локальному объекту, как описано в обсуждении DRbObjects.Это имеет семантику, аналогичную обычной передаче по ссылке в Ruby.

Хорошие новости, она все еще должна работать.Так что не так?Чуть дальше в документации по 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, настроенной на стороне клиента.


Оригинальный ответ

(Я оставлю это здесь, это может меня заинтересовать. Это была точка отдыха намой путь к выяснению всего этого. Это также возможное альтернативное решение. Интересно, что я теперь более осведомленный человек, которого я упомянул, по крайней мере, в отношении причины.)

Вот возможный обходной путь.Похоже, проблема в хэшах, созданных с помощью блока для обработки отсутствующих ключей (который хэш параметров Синатры равен ), поэтому вы можете извлечь содержимое хеша в новый.params.clone и params.merge({}) оба, похоже, сохраняют процесс (вы можете проверить с помощью Hash#default_proc), но {}.merge(params) (или merge!) дает вам хороший чистый хеш, который работает с Drb.

Итак, в этом примере сделайте следующее:

get("/params"){ SERVER.echo({}.merge params).inspect

Почему это происходит с Drb и хэшем с procs, и будет ли это самый простой или самый правильный обходной путь, я оставлюкто-то более знающий.

...