// Process a request coming from a client. func (self *loadBalancer) processClient(client []byte, msg [][]byte) { // Application + Services + Instances if len(msg) < 3 { log.Fatal("Invalid message from client sender") } // Register chain self.registerChain(client, msg) // Start chain of requests self.advanceShackle(self.chains[string(client)]) }
// Dispatch requests to waiting workers as possible func (self *loadBalancer) dispatch(service *lbService, msg [][]byte) { if service == nil { log.Fatal("Nil service") } // Queue message if any if len(msg) != 0 { service.requests = append(service.requests, msg) } self.purgeWorkers() for service.waiting.Len() > 0 && len(service.requests) > 0 { msg, service.requests = service.requests[0], service.requests[1:] elem := service.waiting.Pop() self.waiting.Delete(elem.Value) worker, _ := elem.Value.(*lbWorker) self.sendToWorker(worker, SIGNAL_REQUEST, nil, msg) } }
// Main broker working loop func (self *loadBalancer) Run() { for { items := zmq.PollItems{ zmq.PollItem{Socket: self.frontend, Events: zmq.POLLIN}, zmq.PollItem{Socket: self.backend, Events: zmq.POLLIN}, } _, err := zmq.Poll(items, HEARTBEAT_INTERVAL) if err != nil { log.Fatal("Non items for polling") } if items[0].REvents&zmq.POLLIN != 0 { msg, _ := self.frontend.RecvMultipart(0) // TODO: check msg parts requestId := msg[0] msg = msg[2:] self.processClient(requestId, msg) } if items[1].REvents&zmq.POLLIN != 0 { msg, _ := self.backend.RecvMultipart(0) sender := msg[0] msg = msg[2:] self.processWorker(sender, msg) } if self.heartbeatAt.Before(time.Now()) { self.purgeWorkers() for elem := self.waiting.Front(); elem != nil; elem = elem.Next() { worker, _ := elem.Value.(*lbWorker) self.sendToWorker(worker, SIGNAL_HEARTBEAT, nil, nil) } self.heartbeatAt = time.Now().Add(HEARTBEAT_INTERVAL) } } }
func main() { // Load configuration. var conf = config.New() if err := conf.Load(os.Args[1:]); err != nil { log.Fatal(err.Error() + "\n") } // Enable verbose option. if conf.Verbose { log.Verbose = true } if conf.DataDir == "" { log.Fatal("Data dir does't exist") } // Create data directory if it doesn't already exist. if err := os.MkdirAll(conf.DataDir, 0744); err != nil { log.Fatalf("Unable to create path: %s", err) } // Load etcd configuration. if err := conf.LoadEtcdConfig(); err != nil { log.Fatalf("Unable to load etcd conf: %s", err) } // Launch services var etcd = etcd.New(conf.EtcdConf) etcd.Load() hydraEnv := os.Getenv("HYDRA_ENV") if hydraEnv == "ETCD_TEST" { etcd.Start(true) } else { go func() { var withEtcdServer bool = false if conf.EtcdAddr != "" { withEtcdServer = true } etcd.Start(withEtcdServer) }() connector.SetEtcdConnector(etcd) // Private Server API privateHydraListener, err := net.Listen("tcp", conf.PrivateAddr) if err != nil { log.Fatalf("Failed to create hydra private listener: ", err) } var privateServer = server.NewPrivateServer(privateHydraListener, conf.InstanceExpirationTime) privateServer.RegisterHandlers() go func() { log.Infof("hydra private server [name %s, listen on %s, advertised url %s]", conf.Name, conf.PrivateAddr, "http://"+conf.PrivateAddr) log.Fatal(http.Serve(privateServer.Listener, privateServer.Router)) }() // Public Server API var loadBalancerFrontendEndpoint string = "ipc://" + conf.Name + "-frontend.ipc" publicHydraListener, err := net.Listen("tcp", conf.PublicAddr) if err != nil { log.Fatalf("Failed to create hydra public listener: ", err) } var publicServer = server.NewPublicServer(publicHydraListener, loadBalancerFrontendEndpoint, conf.BalanceTimeout) publicServer.RegisterHandlers() go func() { log.Infof("hydra public server [name %s, listen on %s, advertised url %s]", conf.Name, conf.PublicAddr, "http://"+conf.PublicAddr) log.Fatal(http.Serve(publicServer.Listener, publicServer.Router)) }() // Load applications. var appsConfig = config.NewApplicationsConfig() if _, err := os.Stat(conf.AppsFile); os.IsNotExist(err) { log.Warnf("Unable to find apps file: %s", err) } else { if err := appsConfig.Load(conf.AppsFile); err != nil { log.Fatalf("Unable to load applications: %s", err) } } time.Sleep(1 * time.Second) // Persist Configured applications if err := appsConfig.Persists(); err != nil { log.Fatalf("Failed to save configured applications: ", err) } // Load Balancer loadBalancer := load_balancer.NewLoadBalancer(loadBalancerFrontendEndpoint, "tcp://"+conf.LoadBalancerAddr) defer loadBalancer.Close() loadBalancer.Run() } }