diff --git a/cmd/antelope-api-healtcheck/main.go b/cmd/antelope-api-healtcheck/main.go index 4779a82..94d2ab9 100644 --- a/cmd/antelope-api-healtcheck/main.go +++ b/cmd/antelope-api-healtcheck/main.go @@ -34,6 +34,9 @@ var logfd *os.File var ( logfmt log.Format logger log.Logger + + // TCP Server + srv *server.Server ) // argv_listen_addr @@ -104,6 +107,12 @@ func signalEventLoop() { case syscall.SIGINT, syscall.SIGTERM: l.Info("Program was asked to terminate.") run = false + + // Tell the server to close. + err := srv.Close() + if err != nil { + l.Error("Failed to close server", "error", err) + } // SIGHUP is sent when logfile is rotated. case syscall.SIGHUP: msg := "Logfile was rotated: " @@ -129,7 +138,6 @@ func signalEventLoop() { func main() { var version bool var usage bool - var addr string var logFormatter *string logger = log.Root() @@ -173,23 +181,15 @@ func main() { } } - addr = argv_listen_addr() + // Create server + srv = server.New(argv_listen_addr()) - // Start listening to TCP Connections - srv, err := server.Start(addr) - if err == nil { - logger.Info("TCP Server started", "addr", addr) + // Run signal event loop in its own goroutine + go signalEventLoop() - // Run the signal event loop. - signalEventLoop() - - err = srv.Close() - if err != nil { - logger.Error("Failed to close server", "error", err) - } - } else { - log.Error("Failed to start tcp server", "error", err) + // Run server + err := srv.Run() + if err != nil { + logger.Error("Server failed to shutdown", "message", err) } - - logger.Info("Shutdown") } diff --git a/go.mod b/go.mod index 2bbdc9f..71c2a2e 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/eosswedenorg-go/haproxy v1.0.1 github.com/eosswedenorg-go/leapapi v0.2.2 github.com/eosswedenorg-go/pid v1.0.1 - github.com/eosswedenorg-go/tcp_server v0.2.1 github.com/inconshreveable/log15 v0.0.0-20221122034931-555555054819 + github.com/panjf2000/gnet/v2 v2.2.2 github.com/pborman/getopt/v2 v2.1.0 github.com/stretchr/testify v1.8.1 ) @@ -39,6 +39,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sonh/qs v0.6.2 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect golang.org/x/crypto v0.4.0 // indirect golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 // indirect golang.org/x/mod v0.7.0 // indirect @@ -48,5 +51,6 @@ require ( golang.org/x/text v0.5.0 // indirect golang.org/x/tools v0.4.0 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4567ec6..06144d9 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,11 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -27,8 +30,6 @@ github.com/eosswedenorg-go/leapapi v0.2.2 h1:gNS36V261Y21QjevQ13UV9glb7WbDgdGPbi github.com/eosswedenorg-go/leapapi v0.2.2/go.mod h1:hyfjHswFjcnWMqOb+cYvTrT6l34S80GrFvfOdcYugnM= github.com/eosswedenorg-go/pid v1.0.1 h1:W4AEnnNwb041SpNR1uTZ/KbJ0OTA5eqiqIR1Q5Ah6A0= github.com/eosswedenorg-go/pid v1.0.1/go.mod h1:wiOB/JXGt4YA3+T0j0xmCGSc3Jxzb7Ti/Ftli1fgWu4= -github.com/eosswedenorg-go/tcp_server v0.2.1 h1:xu+b/HfW6cpatBClzZYcM4D7V0u9pqlYVYlIVfntjtI= -github.com/eosswedenorg-go/tcp_server v0.2.1/go.mod h1:3+3QlVIS8UY6eGDP78lg2km6/XFEk/JLbwOr5MfwW/g= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -158,6 +159,9 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/panjf2000/ants/v2 v2.7.1 h1:qBy5lfSdbxvrR0yUnZfaEDjf0FlCw4ufsbcsxmE7r+M= +github.com/panjf2000/gnet/v2 v2.2.2 h1:pTPX34uFB7VMl2p5k/7WspNu58oRqFYq1n6XUhaiBn0= +github.com/panjf2000/gnet/v2 v2.2.2/go.mod h1:Q34YBnJNDFLsVBC4TiGD3uN+imoXrunFnecs/4FYcx4= github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA= github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -210,12 +214,23 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -234,6 +249,7 @@ golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15/go.mod h1:CxIveKay+FTh1D0yPZ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -322,10 +338,12 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= @@ -366,14 +384,19 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= diff --git a/internal/server/server.go b/internal/server/server.go index eec480f..b1ee714 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -1,64 +1,111 @@ package server import ( + "context" + "fmt" "strings" + "time" "github.com/eosswedenorg-go/haproxy/agentcheck" - "github.com/eosswedenorg-go/tcp_server" "github.com/eosswedenorg/antelope-api-healthcheck/internal/api" log "github.com/inconshreveable/log15" + "github.com/panjf2000/gnet/v2" ) -// onTcpMessage callback function -// --------------------------------------------------------- +type Server struct { + gnet.BuiltinEventEngine -func onTcpMessage(c *tcp_server.Client, args string) { + addr string + eng gnet.Engine +} + +func New(addr string) *Server { + return &Server{ + addr: fmt.Sprintf("tcp://%s", addr), + } +} + +// OnBoot callback function +// +// --------------------------------------------------------- +func (s *Server) OnBoot(eng gnet.Engine) gnet.Action { + s.eng = eng + log.Info("Server started", "addr", s.addr) + return gnet.None +} + +// OnShutdown callback function +// +// --------------------------------------------------------- +func (s *Server) OnShutdown(eng gnet.Engine) { + log.Info("Server shutdown") +} + +// OnTick callback function +// +// --------------------------------------------------------- +func (s *Server) OnTick() (time.Duration, gnet.Action) { + log.Info("Server info", "connections", s.eng.CountConnections()) + return time.Second * 10, gnet.None +} + +// OnTraffic callback function +// +// --------------------------------------------------------- +func (s *Server) OnTraffic(c gnet.Conn) gnet.Action { logger := log.Root() + req, err := c.Next(-1) + if err != nil { + logger.Error("Read", "message", err) + return gnet.Close + } + // Check api. // ------------------- - healthCheckApi, err := ParseRequest(args) + healthCheckApi, err := ParseRequest(string(req)) if err != nil { logger.Warn("Agent request error", "message", err) resp := agentcheck.NewStatusMessageResponse(agentcheck.Fail, "") - _, err = c.WriteString(resp.String()) + _, err = c.Write([]byte(resp.String())) if err != nil { - logger.Error("WriteString", "message", err) + logger.Error("Write", "message", err) } - c.Close() - return + return gnet.Close } - status, msg := healthCheckApi.Call() + // gnet library does not like blocking calls. + // as we do a blocking http call here, we need to wrap it in a goroutine. + go func() { + status, msg := healthCheckApi.Call() - params := api.LogParams{} - params.Add("status", strings.TrimSpace(status.String())) + params := api.LogParams{} + params.Add("status", strings.TrimSpace(status.String())) - if msg != "OK" && len(msg) > 0 { - params.Add("error", msg) - } + if msg != "OK" && len(msg) > 0 { + params.Add("error", msg) + } - logger.Info("API Check", params.Combine(healthCheckApi.LogInfo())...) - // Report status to HAproxy - _, err = c.WriteString(status.String()) - if err != nil { - logger.Error("WriteString", "message", err) - } - c.Close() + logger.Info("API Check", params.Combine(healthCheckApi.LogInfo())...) + // Report status to HAproxy + err = c.AsyncWrite([]byte(status.String()), nil) + if err != nil { + logger.Error("Write", "message", err) + } + }() + + return gnet.None } -// Start +func (s *Server) Close() error { + return s.eng.Stop(context.Background()) +} + +// Run the server event loop. +// // --------------------------------------------------------- - -func Start(addr string) (*tcp_server.Server, error) { - server := tcp_server.New(addr) - server.OnMessage(onTcpMessage) - - err := server.Connect() - if err == nil { - err = server.Listen() - } - return server, err +func (s *Server) Run() error { + return gnet.Run(s, s.addr, gnet.WithMulticore(true), gnet.WithTicker(true)) }