I have trouble to pass the variable from a main package into another one.
What I'm trying to do:
I have a simple http daemon which recievs incomming POST requests and pushes them to a rabbitMQ instance where the messages will be handled by some worker. Since the messages can be very big, I try to imlement a simple resource manager. It should accept or denie the request.
This is how it looks like:
package main
import (
"flag"
"fmt"
"github.com/couchbaselabs/logg"
"net/http"
_ "net/http/pprof"
)
var resourceChannel = make(chan bool)
var ampqApiConfig = worker.DefaultResManagerConfig()
var ServiceCanAccept bool
func main() {
var http_port int
flagFunc := func() {
flag.IntVar(
&http_port,
"http_port",
8080,
"The http port to listen on, eg, 8081",
)
}
rabbitConfig := worker.DefaultConfigFlagsOverride(flagFunc)
// any requests to root, just redirect to main page
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
text := `<h1>We are running!<h1>`
fmt.Fprintf(w, text)
})
http.Handle("/req", worker.NewHttpHandler(rabbitConfig))
http.Handle("/status", worker.NewHttpStatusHandler())
listenAddr := fmt.Sprintf(":%d", http_port)
logg.LogTo("HTTP", "Starting listener on %v", listenAddr)
// start a goroutine which will decide if we have resources for future requests
go func() {
for {
resourceChannel <- worker.AcceptRequest(&qApiConfig)
ServiceCanAccept = <-resourceChannel
worker.ServiceCanAccept = ServiceCanAccept
time.Sleep(10 * time.Second)
}
}()
logg.LogError(http.ListenAndServe(listenAddr, nil))
}
I'm defining above a channel and a global variable. Then, I try to run a boolean function(AcceptRequest) every 10 seconds and pass the variable to woker.ServiceCanAccept variable in package "worker". But unfortunately it doesn't work. The goroutine gets executed only once(at least I see the Logs from resource manager only once) and the value of worker.ServiceCanAccept in the target package doesn't change. This is problem number one.
For each request the http.Handle("/req", worker.NewHttpHandler(rabbitConfig))
will be called and ServeHTTP below gets executed. However var ServiceCanAccept bool
never changes. Do I need to create a channel this same name as in package main and read the value from it?
package worker
import (
"encoding/json"
"fmt"
"github.com/couchbaselabs/logg"
"net/http"
)
type HttpHandler struct {
RabbitConfig RabbitConfig
}
func NewHttpHandler(r RabbitConfig) *HttpHandler {
return &HttpHandler{
RabbitConfig: r,
}
}
var ServiceCanAccept bool
func (s *HttpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
logg.LogTo("HTTP", "serveHttp called")
defer req.Body.Close()
Request := Request{}
decoder := json.NewDecoder(req.Body)
err := decoder.Decode(&Request)
if err != nil {
logg.LogError(err)
http.Error(w, "Unable to unmarshal json", 500)
return
}
Result, err := HandleRequest(Request, s.RabbitConfig)
if err != nil {
msg := "Unable to perform decode. Error: %v"
errMsg := fmt.Sprintf(msg, err)
logg.LogError(fmt.Errorf(errMsg))
http.Error(w, errMsg, 500)
return
}
w.Header().Set("Content-Type", "application/json")
js, err := json.Marshal(Result)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(js)
}
func HandleRequest(Request Request, rabbitConfig RabbitConfig) (Result, error) {
defaultResManagerConfig := DefaultResManagerConfig()
if !ServiceCanAccept {
err := fmt.Errorf("no ressources available to proced the request")
return Result{}, err
}
switch Request.InplaceDecode {
case true:
Engine := NewEngine(Request.EngineType)
Result, err := Engine.ProcessRequest(Request)
if err != nil {
msg := "Error processing request. Error: %v"
errMsg := fmt.Sprintf(msg, err)
logg.LogError(fmt.Errorf(errMsg))
return Result{}, err
}
return Result, nil
default:
Client, err := NewRpcClient(rabbitConfig)
if err != nil {
logg.LogError(err)
return Result{}, err
}
Result, err := Client.DecodeImage(Request)
if err != nil {
logg.LogError(err)
return Result{}, err
}
return Result, nil
}
}
Thanks!