Git Product home page Git Product logo

Comments (17)

schmurfy avatar schmurfy commented on September 27, 2024

Looks like a bug in zeromq, I tested this with 2.1.11, I dropped to the C level to try finding the culprit with this: https://gist.github.com/1809376

I used it in front of the em_rep.rb server you posted above without any change.

I tried to mimick what em-zeromq does which is:

  • create a socket
  • get its FD
  • do a select on it (this part is in eventmachine, the direct select call should be close enough)
  • when data arrives on the socket the select call should return and the ruby code executed

With my c code above (it depends on czmq) everything works fine without the select block but if you replace "#if 0" with "#if 1" it will hangs on the select call forever.

It would be great if someone could double check my C code see if there is anything wrong/missing.

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

@schmurfy "The REQ-REP socket pair is lockstep" as per ØMQ Guide - strace of this shows that there is a sendto and a recvmsg happen back to back, since the fd has nothing ready to read, the select hangs. FD_ISSET(fd, &read_set) should return true before your select.

The following works with em-zeromq for me, but looks very hackish. Just a suggestion - I think having the em-zeromq api mirror the zmq api as much as possible would be nice and make it easy for people reading the ØMQ Guide to use it quickly.

module Handler
  def self.on_readable socket, messages
    puts messages.map(&:copy_out_string).first
  end 
end

EM.run do
  context = EM::ZeroMQ::Context.new(1)
  socket  = context.connect(ZMQ::REQ, 'tcp://127.0.0.1:5555', Handler)
  EM.add_periodic_timer(1) do
    socket.send_msg('')
    socket.send(:get_message)
  end 
end

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

There was a stupid mistake in my req.c file, I forgot a "FD_SET(fd, &read_set)" before the select but it changes nothing.
I now have both programs in C and there is still something fishy, I will bring this to the zeromq mailing list see if someone can help me understand what is happening there. I am still not sure if the mistake is mine or if there is problem in zeromq.

Your code may work but your are bypassing completely eventmachine, the ruby code should be notified when data is received and should never call the recv method by itself (or never have to).

What do you mean by mirroring the zmq api ? What would you change ?

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

the ruby code is not bypassing the eventmachine loop, if you notice the on_readable gets triggered.

here's a C example that works, https://gist.github.com/840a4bc2e44992d6e9f9

re. api, it would be nice to conform to http://api.zeromq.org/ for the Context and Connection classes.

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

After some testing I still have no clear idea on what is happening but I may have a solution !

@deepfryed, @baronlinden can you try with the master branch see if you still have issues ?

You will need to replace:

conn.socket.send_string(message)

by this:

conn.send_msg(message)

After a write the library now checks if there are some messages waiting which does nothing really in my tests but somehow the read events are now correctly triggered.

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

yes it works, but only as long as the rep-req rates are low, at higher rates ~100 messages per second the socket goes out of sync.

em-zeromq-test/gems/ruby/1.9.1/bundler/gems/em-zeromq-9e4b07148e51/lib/em-zeromq/connection.rb:73:in `send_msg': Unable to send message: Operation cannot be accomplished in current state (RuntimeError)
        from req.rb:17:in `block (2 levels) in <main>'
        from em-zeromq-test/gems/ruby/1.9.1/gems/eventmachine-1.0.0.beta.4/lib/em/timers.rb:56:in `call'
        from em-zeromq-test/gems/ruby/1.9.1/gems/eventmachine-1.0.0.beta.4/lib/em/timers.rb:56:in `fire'
        from em-zeromq-test/gems/ruby/1.9.1/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:179:in `call'
        from em-zeromq-test/gems/ruby/1.9.1/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:179:in `run_machine'
        from em-zeromq-test/gems/ruby/1.9.1/gems/eventmachine-1.0.0.beta.4/lib/eventmachine.rb:179:in `run'
        from req.rb:12:in `<main>'

but this might be an eventmachine issue, I have not looked into it properly.

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

Honestly I don't like REQ/REP sockets too much, I think they are too simple and XREQ/XREP (now ROUTER/DEALER) sockets fit much better within an eventmachine application.
They serve a purpose I understand for simple clients but if you need to send/receive messages really fast or send/receive messages to and from multiple remotes you better not use them.

I experienced the same problem you got with my REQ client, I suppose the two writes are so close to one another that the zeromq socket did not had the time to properly flush the write to the network socket, since you cannot do two writes before a read zeromq raise an error. This does not happen if you switch to XREQ socket in your client.

if @baronlinden can confirm it works for him I consider this issue fixed.

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

I'm having the same rate limit issue with PUB/SUB with em-zeromq client and c server. The ruby client seems to be stuck in restart_syscall or select.

#!/usr/bin/env ruby

require 'bundler/setup'
require 'em-zeromq'

EM.epoll = true

class MyHandler < EM::ZeroMQ::Connection
  def self.on_readable socket, messages
    messages.each {|message| puts message.copy_out_string}
  end
end

EM.run do
  context    = EM::ZeroMQ::Context.new(1)
  connection = context.connect(ZMQ::SUB, 'tcp://*:5555', MyHandler).tap(&:subscribe)
end
// gcc -o pub pub.c -lzmq

#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    int n = 0;
    void *context = zmq_init(1);
    char *buffer, payload[1024];

    //  socket to talk to clients
    void *socket = zmq_socket(context, ZMQ_PUB);
    zmq_bind(socket, "tcp://*:5555");

    while (1) {
        n = (n + 1) % 1000000;
        snprintf(payload, 1024, "world %d", n);
        zmq_msg_t message;
        zmq_msg_init_size(&message, strlen(payload));
        memcpy(zmq_msg_data(&message), payload, strlen(payload));
        zmq_send(socket, &message, 0);
        zmq_msg_close(&message);
    }

    zmq_close(socket);
    zmq_term(context);
    return 0;
}

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

re. the rate limit issue above, seems to work fine if i set up the connection inside a defer block, so it runs inside the EM thread pool.

from em-zeromq.

baronlinden avatar baronlinden commented on September 27, 2024

@schmurfy I tried calling EM::ZeroMQ::Connection#send_msg instead, but the issue remains.

I agree that the REQ-REP pattern isn't very interesting. I initially wanted to implement the REQ-ROUTER pattern, but I didn't get it to work. So I tried the REQ-REP to test if the gem was working properly and that led to this ticket. Funny enough, I ended up using the ROUTER-DEALER pattern which actually works with this gem.

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

ddi you try with the master branch ?

from em-zeromq.

deepfryed avatar deepfryed commented on September 27, 2024

Hi,

It works for me from master

  • bharanee

from em-zeromq.

baronlinden avatar baronlinden commented on September 27, 2024

Doh! Forgot to try it on master.. It does work. :)

Thanks!

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

great, I will make a release soon but I wanted to clean some things before that.

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

I released 0.2.3 with the fix.

from em-zeromq.

igorw avatar igorw commented on September 27, 2024

I am currently having this same problem with a non-blocking PHP binding. Is REQ/REP not working well with a reactor (not becoming readable on response)? Is the answer to use ROUTER/DEALER instead of REQ/REP?

Cheers!

from em-zeromq.

schmurfy avatar schmurfy commented on September 27, 2024

I don't remember I fixed the bug but it works now.
That said I never used REQ/REP since I usually write asynchronous code I stick with ROUTER/DEALER

from em-zeromq.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.