func (tcp *tcpUnidlerSocket) waitForEndpoints(ch chan<- interface{}, service proxy.ServicePortName, loadBalancer userspace.LoadBalancer) { defer close(ch) for { if loadBalancer.ServiceHasEndpoints(service) { // we have endpoints now, so we're finished return } // otherwise, wait a bit before checking for endpoints again time.Sleep(endpointDialTimeout[0]) } }
// awaitAwakening collects new connections and signals once that pods are needed to fulfill them. The function // will return when the listening socket is closed, which indicates that endpoints have succesfully appeared // (and thus the hybrid proxy has switched this service over to using the normal proxy). Connections will // be gradually timed out and dropped off the list of connections on a per-connection basis. The list of current // connections is returned, in addition to whether or not we should retry this method. func (tcp *tcpUnidlerSocket) awaitAwakening(service proxy.ServicePortName, serviceRef api.ObjectReference, loadBalancer userspace.LoadBalancer, inConns <-chan net.Conn, endpointsAvail chan<- interface{}) (*connectionList, bool) { // collect connections and wait for endpoints to be available sent_need_pods := false timeout_started := false ticker := time.NewTicker(needPodsTickLen) defer ticker.Stop() svcName := fmt.Sprintf("%s/%s:%s", service.Namespace, service.Name, service.Port) allConns := newConnectionList(MaxHeldConnections, needPodsTickLen, needPodsWaitTimeout, svcName) for { select { case inConn, ok := <-inConns: if !ok { // the listen socket has been closed, so we're finished accepting connections return allConns, false } if !sent_need_pods && !loadBalancer.ServiceHasEndpoints(service) { glog.V(4).Infof("unidling TCP proxy sent unidle event to wake up service %s/%s:%s", service.Namespace, service.Name, service.Port) tcp.signaler.NeedPods(serviceRef, service.Port) // only send NeedPods once sent_need_pods = true timeout_started = true } if allConns.Len() == 0 { if !loadBalancer.ServiceHasEndpoints(service) { // notify us when endpoints are available go tcp.waitForEndpoints(endpointsAvail, service, loadBalancer) } } allConns.Add(inConn) glog.V(4).Infof("unidling TCP proxy has accumulated %v connections while waiting for service %s/%s:%s to unidle", allConns.Len(), service.Namespace, service.Name, service.Port) case <-ticker.C: if !timeout_started { continue } // TODO: timeout each connection (or group of connections) separately // timed out, close all waiting connections and reset the state allConns.Tick() } } }