rubyasynchronouscelluloid

Why is the error `Celluloid::Condition signaled spuriously` caused in Celluloid?


I'm trying to wait on a condition of an async code, here's the snippet:

condition = Celluloid::Condition.new   
Rails.logger.debug "Sending RPC request to #{subject}"
NATS.start uri: ENV['NATS_SERVER'] do 
  Rails.logger.debug "Connected to #{ENV['NATS_SERVER']}"
  sid = NATS.request(subject,msg) do |response|
    Rails.logger.debug "Assigning response"
    condition.signal response
    NATS.stop
  end
  NATS.timeout(sid, 1) do
    NATS.stop
    condition.signal ASYNC_ERROR
    raise "One second timeout waiting for a NATS RPC reply from #{subject}"
  end
end

result = condition.wait
if result = ASYNC_ERROR
  raise "Error in RPC call"
else
  return result
end

I get the exception Celluloid::Condition signaled spuriously but there's no extra information and I don't really understand why is it caused and https://github.com/celluloid/celluloid/wiki/Conditions doesn't provide more information.

Why is this caused and how can I fix it?


Solution

  • And to answer your question exactly like your stated question, using a condition.

    Within the scope of an actor:

    class Nats
      include Celluloid
    
      def initialize
        @condition = Celluloid::Condition.new
      end
    
      def start
        Rails.logger.debug "Sending RPC request to #{subject}"
        NATS.start uri: ENV['NATS_SERVER'] do 
          Rails.logger.debug "Connected to #{ENV['NATS_SERVER']}"
          sid = NATS.request(subject,msg) do |response|
            Rails.logger.debug "Assigning response"
            @condition.signal response
            NATS.stop
          end
          NATS.timeout(sid, 1) do
            NATS.stop
            @condition.signal ASYNC_ERROR
            raise "One second timeout waiting for a NATS RPC reply from #{subject}"
          end
        end
      end
    
      def value
        @condition.wait
      end
    end
    
    nats = Nats.new
    nats.async.start
    
    result = nats.value
    if result = ASYNC_ERROR
      raise "Error in RPC call"
    else
      return result
    end
    

    This is even less tested, but ought to show you the basic approach if you aren't going to use a Future like my other answer.