};
// The main task is an LRU queue with heartbeating on workers so we can
// detect crashed or blocked worker tasks:
public static void main(String[] args) {
ZContext ctx = new ZContext ();
Socket frontend = ctx.createSocket(ZMQ.ROUTER);
Socket backend = ctx.createSocket(ZMQ.ROUTER);
frontend.bind( "tcp://*:5555"); // For clients
backend.bind( "tcp://*:5556"); // For workers
// List of available workers
ArrayList<Worker> workers = new ArrayList<Worker> ();
// Send out heartbeats at regular intervals
long heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
while (true) {
PollItem items [] = {
new PollItem( backend, ZMQ.Poller.POLLIN ),
new PollItem( frontend, ZMQ.Poller.POLLIN )
};
// Poll frontend only if we have available workers
int rc = ZMQ.poll (items, workers.size() > 0 ? 2:1,
HEARTBEAT_INTERVAL );
if (rc == -1)
break; // Interrupted
// Handle worker activity on backend
if (items [0].isReadable()) {
// Use worker address for LRU routing
ZMsg msg = ZMsg.recvMsg (backend);
if (msg == null)
break; // Interrupted
// Any sign of life from worker means it's ready
ZFrame address = msg.unwrap();
Worker worker = new Worker(address);
worker.ready(workers);
// Validate control message, or return reply to client
if (msg.size() == 1) {
ZFrame frame = msg.getFirst();
String data = new String(frame.getData());
if (!data.equals(PPP_READY)
&& !data.equals( PPP_HEARTBEAT)) {
System.out.println ("E: invalid message from worker");
msg.dump(System.out);
}
msg.destroy();
}
else
msg.send(frontend);
}
if (items [1].isReadable()) {
// Now get next client request, route to next worker
ZMsg msg = ZMsg.recvMsg (frontend);
if (msg == null)
break; // Interrupted
msg.push(Worker.next(workers));
msg.send( backend);
}
// We handle heartbeating after any socket activity. First we send
// heartbeats to any idle workers if it's time. Then we purge any
// dead workers:
if (System.currentTimeMillis() >= heartbeat_at) {
for (Worker worker: workers) {
worker.address.send(backend,
ZFrame.REUSE + ZFrame.MORE);
ZFrame frame = new ZFrame (PPP_HEARTBEAT);
frame.send(backend, 0);
}
heartbeat_at = System.currentTimeMillis() + HEARTBEAT_INTERVAL;
}
Worker.purge (workers);
}
// When we're done, clean up properly
while ( workers.size() > 0) {
Worker worker = workers.remove(0);
}
workers.clear();
ctx.destroy();
}