duandi8838 2018-12-23 01:16
浏览 93

在循环中执行goroutine并将值传递给另一个包中的变量

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(&ampqApiConfig)
            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!

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
    • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
    • ¥20 腾讯企业邮箱邮件可以恢复么
    • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
    • ¥15 错误 LNK2001 无法解析的外部符号
    • ¥50 安装pyaudiokits失败
    • ¥15 计组这些题应该咋做呀
    • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
    • ¥15 让node服务器有自动加载文件的功能
    • ¥15 jmeter脚本回放有的是对的有的是错的