bvarga / delphizmq

0MQ Delphi binding
GNU Lesser General Public License v3.0
137 stars 63 forks source link

Avoid infinite loops in ZMQPool #21

Closed cpicanco closed 6 years ago

cpicanco commented 7 years ago

Hi, I am not sure if this question is off-topic. Please, just ignore if it is.

Putting a REP inside a POOL will generate an infinite loop when some REQ arrive. Right now I am guessing it is not a bug, it is just a misuse of the framework (please could you confirm?). For example:

  ...
  // Context 1
  FREP  := AContext.Socket( stRep );
  FREP.bind(AREPHost);

  FPoller := TZMQPoller.Create(True, AContext);
  FPoller.Register(FREP,[pePollIn],True);
  ...
  // Context 1 loop
  LCount := FPoller.pool;
  if LCount = 0 then Continue;
  if pePollIn in FPoller.PollItem[0].revents then
    FREP.recv('To infinity and beyond!');   
  ...

  // Context 2
  FREQ :=  AContext.Socket( stReq );
  FREQ.connect(AREPHost);
  FREQ.send('infinite loop inside pool');

Same is valid for srRouter. The way I found to avoid the infinite loop was to delegate the Pooling to a PULL socket on context 1, and to PUSH socket on context 2. For example:

  ...
  // Context 1
  FREP  := AContext.Socket( stRep );
  FREP.bind(AREPHost);

  FPULL := AContext.Socket( stPull );
  FREP.bind(APULLHost);

  FPoller := TZMQPoller.Create(True, AContext);
  FPoller.Register(FPULL,[pePollIn],True);
  ...
  // Context 1 loop
  LCount := FPoller.pool;
  if LCount = 0 then Continue;
  if pePollIn in FPoller.PollItem[0].revents then
    begin
      FPULL.recv(AMessage);
      FREP.recv(''); // just acting as a trigger
      AMessage.Append['Ha, no infinity!']
      FREP.send(AMessage);
    end;   
  ...

  // Context 2
  FREQ :=  AContext.Socket( stReq );
  FREQ.connect(AREPHost);

  FPUSH :=  AContext.Socket( stPush );
  FPUSH.connect(APULLHost);

  FREQ.send(['infinite loop inside pool']);
  FREG.recv(AMessage);
  // AMessage[2] => ''Ha, no infinity!''

So, is the infinity loop a bug or not?

bvarga commented 7 years ago

Hello,

Sounds strange, I think the socket can be REP, sounds like a bug.

The only difference is the type of the socket, if you put a PULL rather than a REP, than everything is fine?

cpicanco commented 7 years ago

Yes, a PULL rather than a REP or ROUTER and everything works just fine. The workaround is doing its job.

cpicanco commented 7 years ago

If anyone is curious about it, please take a look at the full implementation here:

https://github.com/lacs-ufpa/free-mtrix/blob/master/experiment_runner/units/zmq_network.pas