i am starting up a Go API with listenandserve to accept HTTP requests.
How can I achieve the below goal?
current version is completely un-go:
timeout := time.After(10 * time.Minute)
tick := time.Tick(15 * time.Second)
fullcmdfirst := fmt.Sprintf("netstat -anp | grep procname | grep ESTABLISHED | grep -v grep | wc -l")
outputfirst, err1first := exec.Command("/bin/sh", "-c", fullcmdfirst).CombinedOutput()
if strconv.ParseFloat(string(outputfirst)) < 100 {
return nil
}
// Keep trying until we're timed out or lock acquired
for {
select {
// Got a timeout! fail with a timeout error
case <-timeout:
return errors.New("Error: timed out ")
// Got a tick, we should check if we can acquire
case <-tick:
fullcmd := fmt.Sprintf("netstat -anp | grep procname | grep ESTABLISHED | grep -v grep | wc -l")
output, err1 := exec.Command("/bin/sh", "-c", fullcmd).CombinedOutput()
if strconv.ParseFloat(string(outputfirst)) < 100 {
l.Printf("start req")
return nil
}
}
}
There's no need for the netstats or the tickers or any of that (it won't work anyway - as soon as netstat sees <100 connections nothing is stopping the next 100 request from all noticing and you ending up running 199 requests at once; plus, a request that's waiting to be handled is still going to turn up in netstat - throttling connections is a different problem altogether). Just use a buffered channel as a semaphore; it's already thread-safe.
sem := make(chan struct{}, 100)
func myHandler(w http.ResponseWriter, r *http.Request) {
timeout := time.After(10 * time.Minute)
select {
case <- timeout:
http.Error(w, "Sorry", http.StatusUnavailable)
return
case sem <- struct{}:
w.Write([]byte("Hello"))
<- sem
return
}
}
Note though that most clients will have already timed out long before the 10 minute mark.