很多数据竞争Web应用程序

时间:2015-02-03 14:32:17

标签: concurrency go

我正在编写一个Web应用程序。传入请求将首先通过中间件。目前,我已经添加了两个middlwares会话和安全性 在浏览了middlware之后,它将执行请求的处理程序。 会话和安全性middlware将在他们自己的goroutine中执行。

当我测试时,我有很多数据竞争,特别是在middlware部分

WARNING: DATA RACE
Write by goroutine 18:
  runtime.mapassign1()
      c:/go/src/runtime/hashmap.go:383 +0x0
  net/textproto.MIMEHeader.Set()
      c:/go/src/net/textproto/header.go:22 +0xf4
  net/http.Header.Set()
      c:/go/src/net/http/header.go:31 +0x64
  project/middlewares/session.(*ctrl).setHttpHeader()
      D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x9d
  project/middlewares/session.(*ctrl).evaluateJwt()
      D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  project/middlewares/session.(*ctrl).serveHttp()
      D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  project/middlewares/session.func┬À006()
      D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x

Previous write by goroutine 17:
  runtime.mapassign1()
      c:/go/src/runtime/hashmap.go:383 +0x0
  net/textproto.MIMEHeader.Add()
      c:/go/src/net/textproto/header.go:15 +0x212
  net/http.Header.Add()
      c:/go/src/net/http/header.go:24 +0x64
  github.com/unrolled/secure.(*Secure).Process()
      D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe5b
  project/middlewares/security.func┬À001()
      D:/gocode/src/project/middlewares/security/serve_http.go:33 +0

Goroutine 18 (running) created at:
  project/middlewares/session.ServeHttp()
      D:/gocode/src/project/middlewares/session/serve_http.go:29 +0x
  project/middlewares.New()
      D:/gocode/src/project/middlewares/ctrl.go:12 +0x99
  github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Static).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Logger).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  net/http/httptest.(*waitGroupHandler).ServeHTTP()
      c:/go/src/net/http/httptest/server.go:200 +0xfe
  net/http.serverHandler.ServeHTTP()
      c:/go/src/net/http/server.go:1703 +0x1fd
  net/http.(*conn).serve()
      c:/go/src/net/http/server.go:1204 +0x108e

Goroutine 17 (finished) created at:
  project/middlewares/security.ServeHttp()
      D:/gocode/src/project/middlewares/security/serve_http.go:37 +0
  project/middlewares.New()
      D:/gocode/src/project/middlewares/ctrl.go:12 +0x64
  github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Static).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Logger).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  net/http/httptest.(*waitGroupHandler).ServeHTTP()
      c:/go/src/net/http/httptest/server.go:200 +0xfe
  net/http.serverHandler.ServeHTTP()
      c:/go/src/net/http/server.go:1703 +0x1fd
  net/http.(*conn).serve()
      c:/go/src/net/http/server.go:1204 +0x108e
==================
2015/02/03 15:05:31 ctrl.go:17: End of process middlewares
2015/02/03 15:05:31 funcs.go:10: Create new user
2015/02/03 15:05:31 validate.go:14: Validate email thompson@example.com
2015/02/03 15:05:31 validate.go:100: Validate password Test!1234
2015/02/03 15:05:31 validate.go:52: Validate name:  ValidName
2015/02/03 15:05:31 create.go:120: Done
[negroni] Completed 0  in 197ms
PASS
ok      project/testing/account_test 0.664s
PS D:\gocode\src\project\testing\account_test> go test -race
2015/02/03 15:08:10 vs.go:50: Connect to neo4j db.
[negroni] Started POST /user
==================
WARNING: DATA RACE
Write by goroutine 18:
  net/http.(*response).Header()
      c:/go/src/net/http/server.go:615 +0x11a
  github.com/codegangsta/negroni.(*responseWriter).Header()
      <autogenerated>:42 +0x78
  project/middlewares/session.(*ctrl).setHttpHeader()
      D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x68
  project/middlewares/session.(*ctrl).evaluateJwt()
      D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  project/middlewares/session.(*ctrl).serveHttp()
      D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  project/middlewares/session.func┬À006()
      D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x

Previous write by goroutine 17:
  net/http.(*response).Header()
      c:/go/src/net/http/server.go:615 +0x11a
  github.com/codegangsta/negroni.(*responseWriter).Header()
      <autogenerated>:42 +0x78
  github.com/unrolled/secure.(*Secure).Process()
      D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe24
  project/middlewares/security.func┬À001()
      D:/gocode/src/project/middlewares/security/serve_http.go:33 +0

我使用negroni来处理middlwares的工作。

方式,我如何处理middlwares

func New(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {

    if err := process(security.ServeHttp(res, req), session.ServeHttp(res, req)); err != nil {
        res.WriteHeader(http.StatusInternalServerError)
        return
    }

    log.Println("End of process middlewares")
    next(res, req)

}

// Process all middlewares
func process(chErrs ...<-chan error) error {

    for _, chErr := range chErrs {

        // Will abort the loop, when error occurs
        if err := <-chErr; err != nil {
            return err
        }

    }
    return nil
}

正如您所看到的,每个middlware都拥有自己的频道。 for语句将循环,直到错误通道关闭或发送错误。

服务器配置

func Config() *negroni.Negroni {
    n := negroni.Classic()
    n.Use(negroni.HandlerFunc(middlewares.New))
    n.UseHandler(routes.Set())
    return n

}

我的问题是,中间件是原因,为什么我有数据竞争?

1 个答案:

答案 0 :(得分:1)

事实上,你在goroutine中运行中间件就是问题。

如果要并行运行中间件,则必须在内存周围设置一个mutex,该内存由goroutine中执行的任何中间件写入。

在您的特定情况下,您正在撰写和阅读ResponseWriter的{​​{1}}