func (s *Server) RunFrontendServer(frontend *Frontend) {
	if len(frontend.Backends) == 0 {
		log.Fatal(errNoBackend.Error())
	}
	host := frontend.Host
	port := frontend.Port
	address := fmt.Sprintf("%s:%d", host, port)
	for _, backend := range frontend.Backends {
		backend.HeartCheck()
	}
	log.Printf("Run frontend server [%s] at [%s]", frontend.Name, address)
	httpHandle := http.NewServeMux()
	httpHandle.HandleFunc(frontend.Route, func(w http.ResponseWriter, r *http.Request) {
		s.Lock()
		s.Add(1)
		s.Unlock()
		defer func() {
			if rec := recover(); rec != nil {
				log.Println("Err", rec)
				http.Error(w, http.StatusText(http.StatusInternalServerError),
					http.StatusInternalServerError)
			}
		}()
		chanResponse := s.Get(r, frontend)
		defer close(chanResponse)
		r.Close = true
		ticker := time.NewTicker(frontend.Timeout)
		defer ticker.Stop()
		select {
		case result := <-chanResponse:
			for k, vv := range result.Header {
				for _, v := range vv {
					w.Header().Set(k, v)
				}
			}
			s.Lock()
			s.Done()
			s.Unlock()
			if result.Upgraded {
				if s.Configuration.GeneralConfig.Websocket {
					result.HijackWebSocket(w, r)
				}
			} else {
				w.WriteHeader(result.Status)
				if r.Method != "HEAD" {
					w.Write(result.Body)
				}
			}
		case <-r.Cancel:
			s.Lock()
			s.Done()
			s.Unlock()
		case <-ticker.C:
			s.Lock()
			s.Done()
			s.Unlock()
			http.Error(w, errTimeout.Error(), http.StatusRequestTimeout)
		}
	})
	server := &http.Server{
		Addr:    address,
		Handler: httpHandle,
	}
	err := server.ListenAndServe()
	if err != nil {
		log.Fatal(err)
	}
}
Lets run the frontned
package lb
import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"runtime"
	"sync"
	"time"
)
var (
	errNoFrontend  = errors.New("No frontend configuration detected")
	errNoBackend   = errors.New("No backend configuration detected")
	errTimeout     = errors.New("Timeout")
	errPortExists  = errors.New("Port already in use")
	errRouteExists = errors.New("Route already in use")
)
type ShutdownChan chan bool
type Server struct {
	Configuration
	Frontends
	ShutdownChan
	*WorkerPool
	sync.Mutex
	*sync.WaitGroup
}
func NewServer(configuration Configuration) *Server {
	return &Server{
		Configuration: configuration,
		ShutdownChan:  make(ShutdownChan),
		WaitGroup:     &sync.WaitGroup{},
		WorkerPool:    NewWorkerPool(configuration),
	}
}
func (s *Server) setup() {
	runtime.GOMAXPROCS(s.Configuration.GeneralConfig.MaxProcs)
	for _, frontend := range s.Configuration.FrontendsConfig {
		newFrontend := NewFrontend(frontend)
		for _, backend := range frontend.BackendsConfig {
			newFrontend.Backends = append(newFrontend.Backends, NewBackend(backend))
		}
		if err := s.preChecksBeforeAdd(newFrontend); err != nil {
			log.Fatal(err.Error())
		} else {
			s.Frontends = append(s.Frontends, newFrontend)
		}
	}
}
func (s *Server) preChecksBeforeAdd(newFrontend *Frontend) error {
	for _, frontend := range s.Frontends {
		if frontend.Route == newFrontend.Route {
			return errRouteExists
		}
		if frontend.Port == newFrontend.Port {
			return errPortExists
		}
		if len(newFrontend.Backends) == 0 {
			return errNoBackend
		}
	}
	return nil
}