// this function is the goroutine that owns this service - all thread-sensitive data needs to // be manipulated only through here. func (s *Service) mux() { loop: for { select { case slots := <-s.slotsChan: s.Slots += slots s.UpdateCluster() case conn := <-s.connectionChan: s.activeClients.Add(1) // send the server handshake sh := skynet.ServiceHandshake{ Registered: s.Registered, } encoder := bsonrpc.NewEncoder(conn) err := encoder.Encode(sh) if err != nil { s.Log.Item(err) s.activeClients.Done() break } if !s.Registered { conn.Close() s.activeClients.Done() break } // read the client handshake var ch skynet.ClientHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&ch) if err != nil { s.Log.Item(err) s.activeClients.Done() break } // here do stuff with the client handshake go func() { s.RPCServ.ServeCodec(bsonrpc.NewServerCodec(conn)) s.activeClients.Done() }() case register := <-s.registeredChan: if register { s.register() } else { s.unregister() } case _ = <-s.doneChan: go func() { for _ = range s.doneChan { } }() s.RemoveFromCluster() s.doozerChan <- doozerFinish{} break loop } } }
func getConnectionFactory(s *skynet.ServiceInfo) (factory pools.Factory) { factory = func() (pools.Resource, error) { conn, err := net.Dial("tcp", s.Config.ServiceAddr.String()) if err != nil { // TODO: handle failure here and attempt to connect to a different instance return nil, errors.New("Failed to connect to service: " + s.Config.ServiceAddr.String()) } // get the service handshake var sh skynet.ServiceHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&sh) if err != nil { conn.Close() return nil, err } ch := skynet.ClientHandshake{} encoder := bsonrpc.NewEncoder(conn) err = encoder.Encode(ch) if err != nil { conn.Close() return nil, err } if !sh.Registered { // this service has unregistered itself, look elsewhere conn.Close() return factory() } resource := ServiceResource{ rpcClient: bsonrpc.NewClient(conn), service: s, clientID: sh.ClientID, } return resource, nil } return }
func (c *Client) GetServiceFromQuery(q *Query) (s *ServiceClient) { var conn net.Conn var err error s = &ServiceClient{ Log: c.Config.Log, connectionPool: pools.NewRoundRobin(c.Config.ConnectionPoolSize, c.Config.IdleTimeout), query: q, instances: make(map[string]service.Service, 0), } // Load initial list of instances results := s.query.FindInstances() if results != nil { for _, instance := range results { key := instance.Config.ServiceAddr.IPAddress + ":" + strconv.Itoa(instance.Config.ServiceAddr.Port) s.instances[key] = *instance } } go s.monitorInstances() var factory func() (pools.Resource, error) factory = func() (pools.Resource, error) { if len(s.instances) < 1 { return nil, errors.New("No services available that match your criteria") } var key string var instance service.Service // Connect to random instance index := (rand.Int() % len(s.instances)) for k, v := range s.instances { if index == 0 { key = k instance = v break } index-- } conn, err = net.Dial("tcp", instance.Config.ServiceAddr.String()) if err != nil { // TODO: handle failure here and attempt to connect to a different instance return nil, errors.New("Failed to connect to service: " + instance.Config.ServiceAddr.String()) } // get the service handshake var sh skynet.ServiceHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&sh) if err != nil { conn.Close() return nil, err } ch := skynet.ClientHandshake{} encoder := bsonrpc.NewEncoder(conn) err = encoder.Encode(ch) if err != nil { conn.Close() return nil, err } if !sh.Registered { // this service has unregistered itself, look elsewhere conn.Close() delete(s.instances, key) return factory() } resource := ServiceResource{ rpcClient: bsonrpc.NewClient(conn), service: instance, } return resource, nil } s.connectionPool.Open(factory) return s }
// this function is the goroutine that owns this service - all thread-sensitive data needs to // be manipulated only through here. func (s *Service) mux() { loop: for { select { case conn := <-s.connectionChan: atomic.AddInt32(&s.Stats.Clients, 1) clientID := skynet.UUID() s.clientMutex.Lock() s.clientInfo[clientID] = ClientInfo{ Address: conn.RemoteAddr(), } s.clientMutex.Unlock() // send the server handshake sh := skynet.ServiceHandshake{ Registered: s.Registered, ClientID: clientID, } encoder := bsonrpc.NewEncoder(conn) err := encoder.Encode(sh) if err != nil { s.Log.Item(err) atomic.AddInt32(&s.Stats.Clients, -1) break } if !s.Registered { conn.Close() atomic.AddInt32(&s.Stats.Clients, -1) break } // read the client handshake var ch skynet.ClientHandshake decoder := bsonrpc.NewDecoder(conn) err = decoder.Decode(&ch) if err != nil { s.Log.Item(err) atomic.AddInt32(&s.Stats.Clients, -1) break } // here do stuff with the client handshake go func() { s.RPCServ.ServeCodec(bsonrpc.NewServerCodec(conn)) atomic.AddInt32(&s.Stats.Clients, -1) }() case register := <-s.registeredChan: if register { s.register() } else { s.unregister() } case _ = <-s.doneChan: go func() { for _ = range s.doneChan { } }() s.RemoveFromCluster() s.doozerChan <- doozerFinish{} break loop case _ = <-s.updateTicker.C: s.UpdateCluster() } } }