Why do I get random errors by using celluloid?

白昼怎懂夜的黑 提交于 2019-12-24 15:01:18

问题


I need to make API calls to a webservice in order to retrieve date. For this purpose I created a sample in order to get familiar with celluloid. Here I ll user the openweather API for "training" purpose. The ultimate goal is to run multiple requests in concurrently.

my booking class (booking.rb) fetches data

    require 'celluloid'
require 'open-uri'
require 'json'

    class Booking
      include Celluloid


      def initialize

      end

      def parse(url)
        p "back again"
        begin
          buffer = open(url).read
          p JSON.parse(buffer)['cod']
        rescue => e
          "fuck"
        end

      end

    end

and this is how I run it:

require 'celluloid'
Celluloid.shutdown_timeout = 10

begin

  pool = Booking.pool

  %W(
http://api.openweathermap.org/data/2.5/weather?q=London,uk
http://api.openweathermap.org/data/2.5/weather?q=Berlin,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
).each_with_index do |weather, i|
    p i
    #Booking.new.async.parse(weather)
    pool.future.parse(weather)
  end
rescue => e
  p "ex #{e}"
end

p "start"

Now I do get different error messages when I run it several times:

ruby run_booking.rb
0
1
2
3
4
5
6
7
8
9
"start"
D, [2015-06-11T21:20:06.351274 #33316] DEBUG -- : Terminating 9 actors...
E, [2015-06-11T21:20:16.356649 #33316] ERROR -- : Couldn't cleanly terminate all actors in 10 seconds!
➜  booking  ruby run_booking.rb
0
1
2
3
4
5
6
7
8
9
"start"
D, [2015-06-11T21:22:19.172770 #33344] DEBUG -- : Terminating 9 actors...
W, [2015-06-11T21:22:19.173145 #33344]  WARN -- : Terminating task: type=:finalizer, meta={:method_name=>:__shutdown__}, status=:receiving
    Celluloid::TaskFiber backtrace unavailable. Please try `Celluloid.task_class = Celluloid::TaskThread` if you need backtraces here.

So I am wondering what's going on here? Help is appreciated. Thanks in advance


回答1:


0. Your program is finishing before Celluloid does its work.

You need to use the method shown in #2 to avoid that. You need to join each Future to make sure all the information is retrieved and parsed... Otherwise you just fired off a ton of asynchronous calls that do not block ... which means nothing stops the program from exiting.

When in doubt, just add sleep to the end of your program, until you can figure out how you want to gracefully finish. So far the code you showed is incomplete.


1. Use the new version Celluloid like this:

  • https://github.com/celluloid/celluloid/wiki/0.17.0-Prerelease

In your Gemfile:

gem 'celluloid', github: 'celluloid/celluloid', branch: '0.17.0-prerelease', submodules: true

Then when you require the Celluloid library, use this:

require 'celluloid/current'

2. Just use Futures. You don't need a pool at all, it will slow you down:

results = []
booking = Booking.new

%W(
http://api.openweathermap.org/data/2.5/weather?q=London,uk
http://api.openweathermap.org/data/2.5/weather?q=Berlin,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
http://api.openweathermap.org/data/2.5/weather?q=Munich,de
).each_with_index do |weather, i|
  p i
  results << booking.future.parse(weather)
end

#de Turn the futures into actual results by calling `.value` on each future:
results = results.map(&:value)

3. Use http.rb with Celluloid support:

  • https://github.com/httprb/http.rb#celluloidio-support

Add Celluloid::IO to your Gemfile like this:

gem 'celluloid-io', github: 'celluloid/celluloid-io', branch: '0.17.0-dependent', submodules: true

Then use HTTP instead, and pass in Celluloid::IO socket types. Here's the example from http.rb itself:

require "celluloid/io"
require "http"

class HttpFetcher
  include Celluloid::IO

  def fetch(url)
    HTTP.get(url, socket_class: Celluloid::IO::TCPSocket)
  end
end

That call right there uses evented TCP, which goes great with your actor which has concurrent outbound gathering calls.



来源:https://stackoverflow.com/questions/30789795/why-do-i-get-random-errors-by-using-celluloid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!