Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# HyperCache

Check failure on line 1 in README.md

View check run for this annotation

Trunk.io / Trunk Check

prettier

Incorrect formatting, autoformat by running 'trunk fmt'

[![Go](https://github.com/hyp3rd/hypercache/actions/workflows/go.yml/badge.svg)][build-link] [![CodeQL](https://github.com/hyp3rd/hypercache/actions/workflows/codeql.yml/badge.svg)][codeql-link] [![golangci-lint](https://github.com/hyp3rd/hypercache/actions/workflows/golangci-lint.yml/badge.svg)][golangci-lint-link]

Expand Down Expand Up @@ -40,6 +40,31 @@
- Middleware-friendly service wrapper (logging, metrics, tracing, custom)
- Zero-cost if an interval is disabled (tickers are only created when > 0)

### Optional Management HTTP API

You can enable a lightweight management HTTP server to inspect and control a running cache instance.

Add the option when creating the config:

```go
cfg := hypercache.NewConfig[backend.InMemory](constants.InMemoryBackend)
cfg.HyperCacheOptions = append(cfg.HyperCacheOptions,
hypercache.WithManagementHTTP[backend.InMemory]("127.0.0.1:9090"),
)
hc, _ := hypercache.New(context.Background(), hypercache.GetDefaultManager(), cfg)
```

Endpoints (subject to change):

- GET /health – liveness check
- GET /stats – current stats snapshot
- GET /config – sanitized runtime config
- POST /evict – trigger eviction cycle
- POST /trigger-expiration – trigger expiration scan
- POST /clear – clear all items

Bind to 127.0.0.1 by default and wrap with an auth function via `WithMgmtAuth` for production use.

## Installation

Install HyperCache:
Expand Down Expand Up @@ -130,7 +155,7 @@
}
config.InMemoryOptions = []backend.Option[backend.InMemory]{ backend.WithCapacity[backend.InMemory](10) }

cache, err := hypercache.New(hypercache.GetDefaultManager(), config)
cache, err := hypercache.New(context.Background(), hypercache.GetDefaultManager(), config)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
Expand Down
12 changes: 12 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ func ApplyHyperCacheOptions[T backend.IBackendConstrain](cache *HyperCache[T], o
}
}

// WithManagementHTTP enables the optional management HTTP server with the provided address and options.
// addr format example: ":8080" or "127.0.0.1:9090".
func WithManagementHTTP[T backend.IBackendConstrain](addr string, opts ...ManagementHTTPOption) Option[T] {
return func(cache *HyperCache[T]) {
if addr == "" { // noop when empty
return
}

cache.mgmtHTTP = NewManagementHTTPServer(addr, opts...)
}
}

// WithMaxCacheSize is an option that sets the maximum size of the cache.
// The maximum size of the cache is the maximum number of items that can be stored in the cache.
// If the maximum size of the cache is reached, the least recently used item will be evicted from the cache.
Expand Down
2 changes: 2 additions & 0 deletions cspell.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ words:
- GITVERSION
- goccy
- gochecknoglobals
- gofiber
- GOFILES
- gofumpt
- goimports
Expand All @@ -44,6 +45,7 @@ words:
- localmodule
- logrus
- memprofile
- Mgmt
- msgpack
- mvdan
- nestif
Expand Down
16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.25.0

require (
github.com/goccy/go-json v0.10.5
github.com/gofiber/fiber/v3 v3.0.0-beta.5
github.com/hyp3rd/ewrap v1.3.0
github.com/longbridgeapp/assert v1.1.0
github.com/redis/go-redis/v9 v9.12.1
Expand All @@ -15,10 +16,25 @@ require (
)

require (
github.com/andybalholm/brotli v1.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gofiber/schema v1.6.0 // indirect
github.com/gofiber/utils/v2 v2.0.0-rc.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.65.0 // indirect
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/net v0.43.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
39 changes: 39 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
Expand All @@ -8,18 +10,36 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofiber/fiber/v3 v3.0.0-beta.5 h1:MSGbiQZEYiYOqti2Ip2zMRkN4VvZw7Vo7dwZBa1Qjk8=
github.com/gofiber/fiber/v3 v3.0.0-beta.5/go.mod h1:XmI2Agulde26YcQrA2n8X499I1p98/zfCNbNObVUeP8=
github.com/gofiber/schema v1.6.0 h1:rAgVDFwhndtC+hgV7Vu5ItQCn7eC2mBA4Eu1/ZTiEYY=
github.com/gofiber/schema v1.6.0/go.mod h1:WNZWpQx8LlPSK7ZaX0OqOh+nQo/eW2OevsXs1VZfs/s=
github.com/gofiber/utils/v2 v2.0.0-rc.1 h1:b77K5Rk9+Pjdxz4HlwEBnS7u5nikhx7armQB8xPds4s=
github.com/gofiber/utils/v2 v2.0.0-rc.1/go.mod h1:Y1g08g7gvST49bbjHJ1AVqcsmg93912R/tbKWhn6V3E=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hyp3rd/ewrap v1.3.0 h1:hLCIMHsm+AoK2rMwVCYr5ljVHxj+tKTCP0pMMLiOW3Q=
github.com/hyp3rd/ewrap v1.3.0/go.mod h1:IIFZD7fz7CjpWYW2bessFaLvUd3ip9E/ALlz0RE/Tpo=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/longbridgeapp/assert v1.1.0 h1:L+/HISOhuGbNAAmJNXgk3+Tm5QmSB70kwdktJXgjL+I=
github.com/longbridgeapp/assert v1.1.0/go.mod h1:UOI7O3rzlzlz715lQm0atWs6JbrYGuIJUEeOekutL6o=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
Expand All @@ -30,8 +50,18 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.65.0 h1:j/u3uzFEGFfRxw79iYzJN+TteTJwbYkru9uDp3d0Yf8=
github.com/valyala/fasthttp v1.65.0/go.mod h1:P/93/YkKPMsKSnATEeELUCkG8a7Y+k99uxNHVbKINr4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
Expand All @@ -40,6 +70,15 @@ go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/Wgbsd
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
61 changes: 58 additions & 3 deletions hypercache.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type HyperCache[T backend.IBackendConstrain] struct {
statsCollectorName string // `statsCollectorName` holds the name of the stats collector that the cache should use when collecting cache statistics
// StatsCollector to collect cache statistics
StatsCollector stats.ICollector
// Optional management HTTP server
mgmtHTTP *ManagementHTTPServer
}

// NewInMemoryWithDefaults initializes a new HyperCache with the default configuration.
Expand All @@ -91,8 +93,10 @@ func NewInMemoryWithDefaults(capacity int) (*HyperCache[backend.InMemory], error

hcm := GetDefaultManager()

ctx := context.Background()

// Initialize the cache
hyperCache, err := New(hcm, config)
hyperCache, err := New(ctx, hcm, config)
if err != nil {
return nil, err
}
Expand All @@ -106,7 +110,7 @@ func NewInMemoryWithDefaults(capacity int) (*HyperCache[backend.InMemory], error
// - The eviction algorithm is set to LRU.
// - The expiration interval is set to 30 minutes.
// - The stats collector is set to the HistogramStatsCollector stats collector.
func New[T backend.IBackendConstrain](bm *BackendManager, config *Config[T]) (*HyperCache[T], error) {
func New[T backend.IBackendConstrain](ctx context.Context, bm *BackendManager, config *Config[T]) (*HyperCache[T], error) {
// Resolve typed backend from registry
backendTyped, err := resolveBackend(bm, config)
if err != nil {
Expand Down Expand Up @@ -148,6 +152,14 @@ func New[T backend.IBackendConstrain](bm *BackendManager, config *Config[T]) (*H
initExpirationTrigger(hyperCache)
hyperCache.startBackgroundJobs()

// Start optional management HTTP server (non-fatal if start fails)
if hyperCache.mgmtHTTP != nil {
err = hyperCache.mgmtHTTP.Start(ctx, hyperCache) // optional
if err != nil {
hyperCache.mgmtHTTP = nil
}
}

return hyperCache, nil
}

Expand Down Expand Up @@ -859,8 +871,26 @@ func (hyperCache *HyperCache[T]) TriggerEviction() {
}
}

// TriggerExpiration exposes a manual expiration trigger (debounced/coalesced internally).
func (hyperCache *HyperCache[T]) TriggerExpiration() { hyperCache.triggerExpiration() }

// EvictionInterval returns configured eviction interval.
func (hyperCache *HyperCache[T]) EvictionInterval() time.Duration { return hyperCache.evictionInterval }

// ExpirationInterval returns configured expiration interval.
func (hyperCache *HyperCache[T]) ExpirationInterval() time.Duration {
return hyperCache.expirationInterval
}

// EvictionAlgorithm returns eviction algorithm name.
func (hyperCache *HyperCache[T]) EvictionAlgorithm() string { return hyperCache.evictionAlgorithmName }

const (
shutdownTimeout = 2 * time.Second
)

// Stop function stops the expiration and eviction loops and closes the stop channel.
func (hyperCache *HyperCache[T]) Stop() {
func (hyperCache *HyperCache[T]) Stop(ctx context.Context) error {
// Stop the expiration and eviction loops
wg := sync.WaitGroup{}

Expand All @@ -876,6 +906,21 @@ func (hyperCache *HyperCache[T]) Stop() {

hyperCache.once = sync.Once{}
hyperCache.workerPool.Shutdown()

if hyperCache.mgmtHTTP != nil {
ctx, cancel := context.WithTimeout(ctx, shutdownTimeout)
defer cancel()

err := hyperCache.mgmtHTTP.Shutdown(ctx)
if err != nil {
// Handle error
return err
}

cancel()
Copy link

Copilot AI Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context timeout is created but if the shutdown succeeds, cancel() is only called after the successful path. If an error occurs, cancel() is called but the timeout context might still be leaked in some error paths. Move cancel() to a defer statement to ensure it's always called.

Suggested change
cancel()
defer cancel()
err := hyperCache.mgmtHTTP.Shutdown(ctx)
if err != nil {
// Handle error
return err
}

Copilot uses AI. Check for mistakes.
}

return nil
}

// GetStats returns the stats collected by the cache.
Expand All @@ -889,3 +934,13 @@ func (hyperCache *HyperCache[T]) GetStats() stats.Stats {

return stats
}

// ManagementHTTPAddress returns the bound address of the optional management HTTP server.
// Empty string when the server is disabled or failed to start.
func (hyperCache *HyperCache[T]) ManagementHTTPAddress() string {
if hyperCache.mgmtHTTP == nil {
return ""
}

return hyperCache.mgmtHTTP.Address()
}
7 changes: 4 additions & 3 deletions hypercache_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package hypercache

import (
"context"
"testing"
"time"

Expand Down Expand Up @@ -60,7 +61,7 @@ func TestHyperCache_WithExpirationInterval(t *testing.T) {
}
// Test with custom expiration interval
hcm := GetDefaultManager()
cache, err = New(hcm, config)
cache, err = New(context.TODO(), hcm, config)
assert.Nil(t, err)
assert.Equal(t, 1*time.Hour, cache.expirationInterval)
}
Expand All @@ -83,7 +84,7 @@ func TestHyperCache_WithEvictionInterval(t *testing.T) {
}
hcm := GetDefaultManager()
// Test with custom eviction interval
cache, err = New(hcm, config)
cache, err = New(context.TODO(), hcm, config)
assert.Nil(t, err)
assert.Equal(t, 1*time.Hour, cache.evictionInterval)
}
Expand All @@ -106,7 +107,7 @@ func TestHyperCache_WithMaxEvictionCount(t *testing.T) {
},
}
hcm := GetDefaultManager()
cache, err = New(hcm, config)
cache, err = New(context.TODO(), hcm, config)
assert.Nil(t, err)
assert.Equal(t, uint(5), cache.maxEvictionCount)
}
3 changes: 3 additions & 0 deletions internal/sentinel/sentinel.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,7 @@ var (

// ErrTimeoutOrCanceled is returned when a timeout or cancellation occurs.
ErrTimeoutOrCanceled = ewrap.New("the operation timed out or was canceled")

// ErrMgmtHTTPShutdownTimeout is returned when the management HTTP server fails to shutdown before context deadline.
ErrMgmtHTTPShutdownTimeout = ewrap.New("management http shutdown timeout")
)
Loading