diff --git a/go.mod b/go.mod index 3c460547..c3aeff6a 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/aws/aws-sdk-go-v2 v1.18.1 github.com/aws/aws-sdk-go-v2/config v1.18.27 github.com/aws/aws-sdk-go-v2/credentials v1.13.26 - github.com/aws/aws-sdk-go-v2/service/iam v1.20.3 - github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0 + github.com/aws/aws-sdk-go-v2/service/iam v1.21.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.36.0 github.com/bits-and-blooms/bitset v1.8.0 github.com/c-bata/go-prompt v0.2.6 github.com/fatih/color v1.15.0 @@ -45,26 +45,25 @@ require ( github.com/xanzy/go-gitlab v0.86.0 github.com/xhit/go-simple-mail v2.2.2+incompatible github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df golang.org/x/net v0.11.0 golang.org/x/oauth2 v0.9.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.9.0 + golang.org/x/sys v0.10.0 golang.org/x/term v0.9.0 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/clickhouse v0.5.1 gorm.io/driver/mysql v1.5.1 gorm.io/driver/postgres v1.5.2 - gorm.io/driver/sqlite v1.5.1 + gorm.io/driver/sqlite v1.5.2 gorm.io/driver/sqlserver v1.5.1 - gorm.io/gorm v1.25.1 + gorm.io/gorm v1.25.2 ) require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ClickHouse/ch-go v0.57.0 // indirect github.com/ClickHouse/clickhouse-go/v2 v2.10.1 // indirect - github.com/DataDog/zstd v1.5.6-0.20230622172052-ea68dcab66c0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect @@ -98,7 +97,6 @@ require ( github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/pebble v0.0.0-20210331181633-27fc006b8bfb // indirect github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cockroachdb/tokenbucket v0.0.0-20230613231145-182959a1fad6 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/getsentry/sentry-go v0.22.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect @@ -143,7 +141,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/juju/ratelimit v1.0.2 // indirect - github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -155,7 +153,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mattn/go-tty v0.0.5 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microsoft/go-mssqldb v1.1.0 // indirect + github.com/microsoft/go-mssqldb v1.3.0 // indirect github.com/miekg/dns v1.1.55 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -174,7 +172,7 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/segmentio/asm v1.2.0 // indirect @@ -194,13 +192,13 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect - golang.org/x/arch v0.3.0 // indirect + golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.10.0 // indirect - golang.org/x/mod v0.11.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.10.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/logger/hookfile/system.go b/logger/hookfile/system.go index e734bc96..b73e4fec 100644 --- a/logger/hookfile/system.go +++ b/logger/hookfile/system.go @@ -40,6 +40,14 @@ import ( const sizeBuffer = 32 * 1024 +func (o *hkf) newBuffer(size int) *bytes.Buffer { + if size > 0 { + return bytes.NewBuffer(make([]byte, 0, size)) + } + + return bytes.NewBuffer(make([]byte, 0, sizeBuffer)) +} + func (o *hkf) writeBuffer(buf *bytes.Buffer) error { var ( e error @@ -48,6 +56,7 @@ func (o *hkf) writeBuffer(buf *bytes.Buffer) error { m = o.getFileMode() n = o.getPathMode() f = o.getFlags() + b = o.newBuffer(0) ) if o.getCreatePath() { @@ -57,6 +66,9 @@ func (o *hkf) writeBuffer(buf *bytes.Buffer) error { } defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } if h != nil { _ = h.Close() } @@ -68,32 +80,37 @@ func (o *hkf) writeBuffer(buf *bytes.Buffer) error { return e } else if _, e = h.Write(buf.Bytes()); e != nil { return e - } else if e = h.Close(); e != nil { - h = nil - buf.Reset() - return e - } else { - h = nil } - buf.Reset() - return nil + *buf = *b + e = h.Close() + h = nil + + return e } func (o *hkf) freeBuffer(buf *bytes.Buffer, size int) *bytes.Buffer { - var a = bytes.NewBuffer(buf.Bytes()[size:]) - a.Grow(size) + defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } + }() + var a = o.newBuffer(buf.Cap()) + a.WriteString(buf.String()[size:]) return a } func (o *hkf) Run(ctx context.Context) { var ( - b = bytes.NewBuffer(make([]byte, sizeBuffer)) + b = o.newBuffer(0) t = time.NewTicker(time.Second) e error ) defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } //flush buffer before exit function if b.Len() > 0 { if e = o.writeBuffer(b); e != nil { @@ -123,9 +140,11 @@ func (o *hkf) Run(ctx context.Context) { case p := <-o.Data(): // prevent buffer overflow - if b.Len()+len(p) >= sizeBuffer { - b = o.freeBuffer(b, len(p)) - b.Write(p) + if b.Len()+len(p) >= b.Cap() { + if a := o.freeBuffer(b, len(p)); a != nil { + b = a + b.Write(p) + } } else { _, _ = b.Write(p) } diff --git a/logger/hooksyslog/system.go b/logger/hooksyslog/system.go index 391037ba..40b560f3 100644 --- a/logger/hooksyslog/system.go +++ b/logger/hooksyslog/system.go @@ -30,6 +30,7 @@ package hooksyslog import ( "context" "fmt" + "os" "sync" "time" ) @@ -42,6 +43,9 @@ func (o *hks) Run(ctx context.Context) { ) defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } if s != nil { w.Wait() _ = s.Close() @@ -78,7 +82,12 @@ func (o *hks) Run(ctx context.Context) { func (o *hks) writeWrapper(w Wrapper, d data, done func()) { var err error - defer done() + defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } + done() + }() if w == nil { return diff --git a/server/runner/ticker/model.go b/server/runner/ticker/model.go index 49dee7e3..b56c43f5 100644 --- a/server/runner/ticker/model.go +++ b/server/runner/ticker/model.go @@ -29,6 +29,8 @@ package ticker import ( "context" "errors" + "fmt" + "os" "sync" "time" ) @@ -98,6 +100,9 @@ func (o *run) Start(ctx context.Context) error { ) defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic thread.\n%v\n", rec) + } if n != nil { n() } @@ -113,7 +118,15 @@ func (o *run) Start(ctx context.Context) error { for { select { case <-tck.C: - if e := fct(x, tck); e != nil { + f := func(ctx context.Context, tck *time.Ticker) error { + defer func() { + if rec := recover(); rec != nil { + _, _ = fmt.Fprintf(os.Stderr, "recovering panic calling function.\n%v\n", rec) + } + }() + return fct(ctx, tck) + } + if e := f(x, tck); e != nil { o.errorsAdd(e) } case <-con.Done(): diff --git a/status/cache.go b/status/cache.go new file mode 100644 index 00000000..45d1af05 --- /dev/null +++ b/status/cache.go @@ -0,0 +1,66 @@ +/* + * MIT License + * + * Copyright (c) 2022 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package status + +import ( + "sync/atomic" + "time" +) + +const timeCache = 3 * time.Second + +type ch struct { + t *atomic.Value + c *atomic.Bool + f func() bool +} + +func (o *ch) Time() time.Time { + if t := o.t.Load(); t != nil { + return t.(time.Time) + } else { + return time.Time{} + } +} + +func (o *ch) IsCache() bool { + if t := o.Time(); !t.IsZero() && time.Since(t) < timeCache { + return o.c.Load() + } + + if o.f != nil { + c := o.f() + o.c.Store(c) + + t := time.Now() + o.t.Store(t) + + return c + } + + return false +} diff --git a/status/interface.go b/status/interface.go index fcef5892..099895c5 100644 --- a/status/interface.go +++ b/status/interface.go @@ -29,6 +29,7 @@ package status import ( "context" "sync" + "sync/atomic" liberr "github.com/nabbar/golib/errors" @@ -64,16 +65,29 @@ type Status interface { SetConfig(cfg Config) IsHealthy(name ...string) bool + IsCacheHealthy() bool } func New(ctx libctx.FuncContext) Status { - return &sts{ - m: sync.RWMutex{}, - p: nil, - x: libctx.NewConfig[string](ctx), + s := &sts{ + m: sync.RWMutex{}, + p: nil, + r: nil, + x: libctx.NewConfig[string](ctx), + c: ch{ + t: new(atomic.Value), + c: new(atomic.Bool), + f: nil, + }, fn: nil, fr: nil, fh: nil, fd: nil, } + + s.c.f = func() bool { + return s.IsHealthy() + } + + return s } diff --git a/status/model.go b/status/model.go index 5a658672..54f96672 100644 --- a/status/model.go +++ b/status/model.go @@ -49,6 +49,7 @@ type sts struct { p montps.FuncPool r func() liberr.ReturnGin x libctx.Config[string] + c ch fn fctGetName fr fctGetRelease @@ -63,6 +64,10 @@ func (o *sts) checkFunc() bool { return o.fn != nil && o.fr != nil && o.fh != nil && o.fd != nil } +func (o *sts) IsCacheHealthy() bool { + return o.c.IsCache() +} + func (o *sts) IsHealthy(name ...string) bool { s, _ := o.getStatus(name...) return s == monsts.OK