EzDevInfo.com

celluloid

Actor-based concurrent object framework for Ruby Celluloid: Actor-based Concurrent Objects for Ruby celluloid is an actor-based concurrent object oriented programming framework for the ruby programming language

Sinatra + websocket + Celluloid

Hi does anybody know how to put in place a quick code example of a Sinatra app running on top of Celluloid:IO and using websocket?

I know of the existance of Reel for Celluloid ("Reel is a fast, non-blocking "evented" web server built on top of Celluloid:IO" which by the way also supports Octarine, a "Sinatra-like DSL for writing a HTTP routing proxy." ... and supports websockets straight away) but nonetheless I'd like to keep using Sinatra because I've become accustomed with it, and I'd prefer not to rewrite a lot of code...

Hope you can help.


Source: (StackOverflow)

Wrong number of arguments when run compass watch

When I run "compass watch" I got this error:

LoadError on line ["54"] of /usr/local/lib/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb: cannot load such file -- susy
Run with --trace to see the full backtrace

I managed to fix it with:

sudo gem update
sudo gem install susy

When I run compass again, css files were generated and I got a new error:

>>> Compass is watching for changes. Press Ctrl-C to Stop.
    write css/ie10_and_higher.css
    write css/ie9.css
    write css/style.css
D, [2015-07-31T10:36:12.805795 #5675] DEBUG -- : Celluloid 0.17.0 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
ArgumentError on line ["48"] of /var/lib/gems/2.1.0/gems/celluloid-0.17.0/lib/celluloid/calls.rb: wrong number of arguments (2 for 1)
Run with --trace to see the full backtrace

And now I can't find any solution in google.


Source: (StackOverflow)

Advertisements

Sidekiq current Celluloid Actor

I need to access the current celluloid actor inside of my Sidekiq worker, but I don't see a way to do that.

Whenever I try to call:

Celluloid::Actor.current

I get an error: not in actor scope

I tried to get around finding the current actor by creating a new one every time with:

Celluloid::Actor.new(SecureRandom.hex)

But for some reason it was giving me an error of attempted to call dead actor.

What should I be doing differently to get the current actor inside of a Sidekiq worker?

Background Info I am connecting to a websocket in my worker and sending messages to it.

Celluloid::WebSocket::Client.new('ws://my-uri', Celluloid::Actor.current)


Source: (StackOverflow)

Ruby & Celluloid

due to some limitations I wanna switch my current project from EventMachine/EM-Synchrony to Celluloid but I've some trouble to get in touch with it. The project I am coding on is a web harvester which should crawl tons of pages as fast as possible.

For the basic understanding of Celluloid I've generated 10.000 dummy pages on a local web server and wanna crawl them by this simple Celluloid snippet:

#!/usr/bin/env jruby --1.9

require 'celluloid'
require 'open-uri'

IDS = 1..9999
BASE_URL = "http://192.168.0.20/files"

class Crawler
  include Celluloid
  def read(id)
    url = "#{BASE_URL}/#{id}"
    puts "URL: " + url
    open(url) { |x| x.read }
  end
end

pool = Crawler.pool(size: 100)

IDS.to_a.map do |id|
   pool.future(:read, id)
end

As far as I understand Celluloid, futures are the way to go to get the response of a fired request (comparable to callbacks in EventMachine), right? The other thing is, every actor runs in its own thread, so I need some kind of batching the requests cause 10.000 threads would result in errors on my OSX dev machine. So creating a pool is the way to go, right? BUT: the code above iterates over the 9999 URLs but only 1300 HTTP requests are sent to the web server. So something goes wrong with limiting the requests and iterating over all URLs. Anyone has a hint?

Cheerio, Chris


Source: (StackOverflow)

Celluloid callback

How can I get notified when an async method has finished it's job (callback) when using Celluloid?

Sample code:

  require 'celluloid/autostart'

  class Test
    include Celluloid

    def initialize(aaa)
      @aaa = aaa
    end

    def foo
      sleep 20
      @bbb = 'asdasd'
    end

    def bar
      "aaa is: #{@aaa}, bbb is: #{@bbb}"
    end
  end
  x = Test.new 111
  x.async.foo

I would like to get notified as soon as the job inside foo is done.


Source: (StackOverflow)

Error in celluloid gem installtion

Recently I have update my rails version to 4.2.3 and ruby version to ruby-2.2.3. After that when I do bundle it gives following error:

$ bundle
Fetching gem metadata from http://rubygems.org/..........
Fetching version metadata from http://rubygems.org/...
Fetching dependency metadata from http://rubygems.org/..
Could not find celluloid-0.16.1 in any of the sources

Could you help me?


Source: (StackOverflow)

How can I parallize the execution of my plugins with Celluloid?

My question should help me to get on the right way.

I'm developing a ruby application with the concurrent framework celluloid. Here how it looks like:

activity

I have some plugins. I want to run them concurrently and wait until the last one has finished. I've an abstract class, called PluginFrame, which is inherited by all the plugin and which also provides a run method.

  1. My idea was to make a SupervisionGroup, but is that the right idea?
  2. How can I run a SupervisionGroup and wait until all group members have finished?
  3. It's a good idea to make a separate PluginPool class, to manage the pool of plugins?
  4. It's also interesting for me to limit the pool size, so only two or three plugins run at the same time.How can I achieve this?

Source: (StackOverflow)

Proper way to maintain many connections with Celluloid?

I am currently working on an application that pulls mail from many IMAP mailboxes. It seems like Celluloid is a goot fit for this part, but I'm unsure on how to employ actors.

The application will be run in a distributed fashion. There are x mailboxes to poll and y processes among which these will be divided. So each process has a list of mailboxes they have to poll and this list will change every now and then. This means the pool of connections maintained by each process is dynamic.

My biggest question is: should I spawn a separate ImapConnection actor for each mailbox, or should I make a single ImapListener actor that manages all connections internally?

My current design features the former solution. There's one central Coordinator actor that keeps an array of actors that each manage one imap connection. A new connection is added with a simple:

@connections << ImapConnection.supervise(account_info)

The ImapConnection either polls the IMAP server at regular intervals, or maintains an IDLE connection. If the Coordinator wants to stop polling a mailbox it looks it up in its @connections array and properly disposes of it.

This seems like a logical approach for me that yields many benefits of Celluloid (such as automatic restarting of crashed actors), but I'm struggling to find examples of other software that uses this approach. Is spawning 100's of actors in this fashion proper use of the actor model or should I use a different approach?


Source: (StackOverflow)

celluloid task was terminated

When using Guard, I get the following error when running bundle exec guard under cygwin. I can't seem to find much on this error other than this issue:

stack level too deep (SystemStackError) · Issue #172 · guard/listen · GitHub

Does anybody know the cause? Or whether Guard works under cygwin at all?

/usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/tasks/task_fiber.rb:32:in `terminate': task was terminated (Celluloid::Task::TerminatedError)
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:404:in `block in cleanup'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:404:in `each'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:404:in `cleanup'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:375:in `shutdown'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:367:in `handle_crash'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:187:in `rescue in run'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:171:in `run'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/actor.rb:157:in `block in initialize'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/thread_handle.rb:13:in `block in initialize'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/internal_pool.rb:100:in `call'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/internal_pool.rb:100:in `block in create'
    from (celluloid):0:in `remote procedure call'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/calls.rb:92:in `value'
    from /usr/lib/ruby/gems/1.9.1/gems/celluloid-0.15.2/lib/celluloid/proxies/sync_proxy.rb:33:in `method_missing'
    from /usr/lib/ruby/gems/1.9.1/gems/listen-2.7.4/lib/listen/listener.rb:131:in `_init_actors'
    from /usr/lib/ruby/gems/1.9.1/gems/listen-2.7.4/lib/listen/listener.rb:38:in `start'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/lib/guard/commander.rb:30:in `block in start'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/lib/guard/commander.rb:108:in `block in within_preserved_state'
    from <internal:prelude>:10:in `synchronize'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/lib/guard/commander.rb:105:in `within_preserved_state'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/lib/guard/commander.rb:26:in `start'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/lib/guard/cli.rb:101:in `start'
    from /usr/lib/ruby/gems/1.9.1/gems/thor-0.19.1/lib/thor/command.rb:27:in `run'
    from /usr/lib/ruby/gems/1.9.1/gems/thor-0.19.1/lib/thor/invocation.rb:126:in `invoke_command'
    from /usr/lib/ruby/gems/1.9.1/gems/thor-0.19.1/lib/thor.rb:359:in `dispatch'
    from /usr/lib/ruby/gems/1.9.1/gems/thor-0.19.1/lib/thor/base.rb:440:in `start'
    from /usr/lib/ruby/gems/1.9.1/gems/guard-2.4.0/bin/guard:6:in `<top (required)>'
    from /usr/bin/guard:23:in `load'
    from /usr/bin/guard:23:in `<main>'

My Guardfile:

guard 'rspec' do
  # watch /lib/ files
  watch(%r{^lib/(.+).rb$}) do |m|
    "spec/#{m[1]}_spec.rb"
  end

  # watch /spec/ files
  watch(%r{^spec/(.+).rb$}) do |m|
    "spec/#{m[1]}.rb"
  end
end

Any help is appreciated!


Source: (StackOverflow)

How to design and structure a program that uses Actors

From Joe Armstrong's dissertation, he specified that an Actor-based program should be designed by following three steps. The thing is, I don't understand how the steps map to a real world problem or how to apply them. Here's Joe's original suggestion.

  1. We identify all the truly concurrent activities in our real world activity.
  2. We identify all message channels between the concurrent activities.
  3. We write down all the messages which can flow on the different message channels. Now we write the program. The structure of the program should exactly follow the structure of the problem. Each real world concurrent activity should be mapped onto exactly one concurrent process in our programming language. If there is a 1:1 mapping of the problem onto the program we say that the program is isomorphic to the problem.

It is extremely important that the mapping is exactly 1:1. The reason for this is that it minimizes the conceptual gap between the problem and the solution. If this mapping is not 1:1 the program will quickly degenerate, and become difficult to understand. This degeneration is often observed when non-CO languages are used to solve concurrent problems. Often the only way to get the program to work is to force several independent activities to be controlled by the same language thread or process. This leads to an inevitable loss of clarity, and makes the programs subject to complex and irreproducible interference errors.

I think #1 is fairly easy to figure out. It's #2 (and 3) where I get lost. To illustrate my frustration I stubbed out a small service available in this gist (Ruby service with callbacks).

Looking at that example service I can see how to answer #1. We have 5 concurrent services.

  1. Start
  2. LoginGateway
  3. LogoutGateway
  4. Stop
  5. Subscribe

Some of those services don't work (or shouldn't) depending on the state the service is in. If the service hasn't been Started, then Login/Logout/Subscribe make no sense. Does this kind of state information have any relevance to Joe's 3 steps?

Anyway, given the example/mock service in that gist, I'm wondering how someone would go about designing a program to wrap this service up in an Actory fashion. I would just like to see a list of guidelines on how to apply Joe's 3 steps. Bonus points for writing some code (any language).


Source: (StackOverflow)

How to use Rails as DDP server with Meteor.js client

We have a Rails app that acts HTTP API only. On the client side, Ember.js is currently used. We are not overly impressed by Ember and really like the approach Meteor.js takes. So we'd like to exchange the client side with Meteor.js and communicate with the Rails server via websockets that speak the Data Distribution Protocol (DDP), so we can keep using the models, mailers and controllers in Rails. Implementing server side of DDP should be easy.

However, we're unsure how to make Rails talk websockets. We found Reel, which seems to make it easy to accept websocket requests in a standalone environment. Reel seems great as we'd like to implement the DDP on top of the Celluloid stack anyway. But what about running Reel in the Rails environment? Would we need "rails runner" for that? And we'd like to keep using the existing controllers to dispatch incoming requests (like, to add/change/remove resources). Is that even possible without having the request coming through Rack?

Any input is appreciated.


Source: (StackOverflow)

Ruby's best way to process thousand async requests?

The task is to process quote ticks almost realtime ( 1 second delay ).

At the moment I need to process about hundred quotes but it might increase to thousands. I'm looking at the EM currently to run ten threads each of which will run ten async requests and put data into some PubSub for later processing.

Also I'm testing Celluloid-IO with HTTP gem.

Am I on the right way? Tried to check GitHub for smth that I'm trying to implement but failed.


Source: (StackOverflow)

How do I run HTTP requests from a pool of threads using Celluloid?

I'm using Ruby 1.9.3, and testing it on Mac OSX 10.7.

I have a Sender class which is supposed to send requests to some URL:

require "celluloid"
require "curb"

class Sender
  include Celluloid

  def send(msg)    
    Curl.get($URL) do |url|
      url.headers["content-type"] = "text/html;charset=utf-8"
    end
  rescue Exception => e
    $LOG.error "[erro]-> [ #{e.message} "
  end
end

I have another process which is supposed to receive messages from a RabbitMQ queue and send requests using Sender:

 AMQP.start(:host => $AMQP_URL) do |connection|
   @channel ||= AMQP::Channel.new(connection)
   @queue   ||= @channel.queue("results")

   pool = Sender.pool

   @queue.subscribe do |metadata, body|
      msg = MessagePack.unpack(body)        
      pool.send(msg)
  end
 end

When I run it I'm getting:

15:56:59 results.1    | I, [2013-02-12T15:56:59.422192 #44490]  INFO -- : Terminating 5 actors...
15:56:59 results.1    | E, [2013-02-12T15:56:59.422640 #44490] ERROR -- : Celluloid::PoolManager crashed!
15:56:59 results.1    | NoMethodError: undefined method `each' for nil:NilClass
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/macosx.rb:39:in `<top (required)>'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:81:in `load'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:81:in `load_file'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:43:in `block (2 levels) in load_all'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:38:in `each'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:38:in `block in load_all'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:35:in `each'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:35:in `load_all'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/collection.rb:72:in `fact'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter.rb:94:in `block (2 levels) in singletonclass'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid.rb:37:in `cores'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/pool_manager.rb:12:in `initialize'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/calls.rb:57:in `dispatch'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/actor.rb:323:in `block in handle_message'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
15:56:59 results.1    | E, [2013-02-12T15:56:59.423117 #44490] ERROR -- : Celluloid::PoolManager#finalize crashed!
15:56:59 results.1    | NoMethodError: undefined method `+' for nil:NilClass
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/pool_manager.rb:26:in `finalize'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/actor.rb:376:in `block in run_finalizer'
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
15:56:59 results.1    | I, [2013-02-12T15:56:59.424508 #44490]  INFO -- : Shutdown completed cleanly
15:56:59 results.1    | /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/macosx.rb:39:in `<top (required)>': undefined method `each' for nil:NilClass (NoMethodError)
15:56:59 results.1    |   from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:81:in `load'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:81:in `load_file'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:43:in `block (2 levels) in load_all'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:38:in `each'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:38:in `block in load_all'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:35:in `each'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/loader.rb:35:in `load_all'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter/util/collection.rb:72:in `fact'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/facter-1.6.13/lib/facter.rb:94:in `block (2 levels) in singletonclass'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid.rb:37:in `cores'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/pool_manager.rb:12:in `initialize'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/calls.rb:57:in `dispatch'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/actor.rb:323:in `block in handle_message'
15:56:59 results.1    |     from /Users/info/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/gems/1.9.1/gems/celluloid-0.12.3/lib/celluloid/tasks/task_fiber.rb:22:in `block in initialize'
15:56:59 results.1    | exited with code 1

Am I doing anything wrong to make the processes crash because of the pool manager?


Source: (StackOverflow)

Ruby: Connect to remote WebSocket

I'm trying to connect to remote websocket using Celluloid and Websocket client based on celluloid (gem 'celluloid-websocket-client'). The main advantage of this client for me is that I can use callbacks in the form of class methods instead of blocks.

require 'celluloid/websocket/client'
class WSConnection
  include Celluloid

  def initialize(url)
    @ws_client = Celluloid::WebSocket::Client.new url, Celluloid::Actor.current
  end

  # When WebSocket is opened, register callbacks
  def on_open
    puts "Websocket connection opened"
  end

  # When raw WebSocket message is received
  def on_message(msg)
    puts "Received message: #{msg}"
  end

  # When WebSocket is closed
  def on_close(code, reason)
    puts "WebSocket connection closed: #{code.inspect}, #{reason.inspect}"
  end

end

m = WSConnection.new('wss://foo.bar')

while true; sleep; end

The expected output is

"Websocket connection opened"

However, I don't get any output at all. What could be the problem?

I am using

gem 'celluloid-websocket-client', '0.0.2'
rails 4.2.1
ruby 2.1.3

Source: (StackOverflow)

Gracefully disconnect a WebSocket connection with Celluloid

Situation

I connect to a WebSocket with Chrome's Remote Debugging Protocol, using a Rails application and a class that implements Celluloid, or more specifically, celluloid-websocket-client.

The problem is that I don't know how to disconnect the WebSocket cleanly.

When an error happens inside the actor, but the main program runs, Chrome somehow still makes the WebSocket unavailable, not allowing me to attach again.

Code Example

Here's the code, completely self-contained:

require 'celluloid/websocket/client'

class MeasurementConnection

  include Celluloid

  def initialize(url)
    @ws_client = Celluloid::WebSocket::Client.new url, Celluloid::Actor.current
  end

  # When WebSocket is opened, register callbacks
  def on_open
    puts "Websocket connection opened"
    # @ws_client.close to close it
  end

  # When raw WebSocket message is received
  def on_message(msg)
    puts "Received message: #{msg}"
  end

  # Send a raw WebSocket message
  def send_chrome_message(msg)
    @ws_client.text JSON.dump msg
  end

  # When WebSocket is closed
  def on_close(code, reason)
    puts "WebSocket connection closed: #{code.inspect}, #{reason.inspect}"
  end

end

MeasurementConnection.new ARGV[0].strip.gsub("\"","")
while true
  sleep
end

What I've tried

  • When I uncomment @ws_client.close, I get:

    NoMethodError: undefined method `close' for #<Celluloid::CellProxy(Celluloid::WebSocket::Client::Connection:0x3f954f44edf4)
    

    But I thought this was delegated? At least the .text method works too?

  • When I call terminate instead (to quit the Actor), the WebSocket is still opened in the background.

  • When I call terminate on the MeasurementConnection object that I create in the main code, it makes the Actor appear dead, but still does not free the connection.

How to reproduce

You can test this yourself by starting Chrome with --remote-debugging-port=9222 as command-line argument, then checking curl http://localhost:9222/json and using the webSocketDebuggerUrl from there, e.g.:

ruby chrome-test.rb $(curl http://localhost:9222/json 2>/dev/null | grep webSocket | cut -d ":" -f2-)

If no webSocketDebuggerUrl is available, then something is still connecting to it.

It used to work when I was using EventMachine similar to this example, but not with faye/websocket-client, but em-websocket-client instead. Here, upon stopping the EM loop (with EM.stop), the WebSocket would become available again.


Source: (StackOverflow)