89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
//
|
|
// Simple Pirate broker.
|
|
// This is identical to load-balancing pattern, with no reliability
|
|
// mechanisms. It depends on the client for recovery. Runs forever.
|
|
//
|
|
|
|
package main
|
|
|
|
import (
|
|
zmq "github.com/pebbe/zmq4"
|
|
)
|
|
|
|
const (
|
|
WORKER_READY = "\001" // Signals worker is ready
|
|
)
|
|
|
|
func main() {
|
|
frontend, _ := zmq.NewSocket(zmq.ROUTER)
|
|
backend, _ := zmq.NewSocket(zmq.ROUTER)
|
|
defer frontend.Close()
|
|
defer backend.Close()
|
|
frontend.Bind("tcp://*:5555") // For clients
|
|
backend.Bind("tcp://*:5556") // For workers
|
|
|
|
// Queue of available workers
|
|
workers := make([]string, 0)
|
|
|
|
poller1 := zmq.NewPoller()
|
|
poller1.Add(backend, zmq.POLLIN)
|
|
poller2 := zmq.NewPoller()
|
|
poller2.Add(backend, zmq.POLLIN)
|
|
poller2.Add(frontend, zmq.POLLIN)
|
|
|
|
// The body of this example is exactly the same as lbbroker2.
|
|
LOOP:
|
|
for {
|
|
// Poll frontend only if we have available workers
|
|
var sockets []zmq.Polled
|
|
var err error
|
|
if len(workers) > 0 {
|
|
sockets, err = poller2.Poll(-1)
|
|
} else {
|
|
sockets, err = poller1.Poll(-1)
|
|
}
|
|
if err != nil {
|
|
break // Interrupted
|
|
}
|
|
for _, socket := range sockets {
|
|
switch s := socket.Socket; s {
|
|
case backend: // Handle worker activity on backend
|
|
// Use worker identity for load-balancing
|
|
msg, err := s.RecvMessage(0)
|
|
if err != nil {
|
|
break LOOP // Interrupted
|
|
}
|
|
var identity string
|
|
identity, msg = unwrap(msg)
|
|
workers = append(workers, identity)
|
|
|
|
// Forward message to client if it's not a READY
|
|
if msg[0] != WORKER_READY {
|
|
frontend.SendMessage(msg)
|
|
}
|
|
|
|
case frontend:
|
|
// Get client request, route to first available worker
|
|
msg, err := s.RecvMessage(0)
|
|
if err == nil {
|
|
backend.SendMessage(workers[0], "", msg)
|
|
workers = workers[1:]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pops frame off front of message and returns it as 'head'
|
|
// If next frame is empty, pops that empty frame.
|
|
// Return remaining frames of message as 'tail'
|
|
func unwrap(msg []string) (head string, tail []string) {
|
|
head = msg[0]
|
|
if len(msg) > 1 && msg[1] == "" {
|
|
tail = msg[2:]
|
|
} else {
|
|
tail = msg[1:]
|
|
}
|
|
return
|
|
}
|