Skip to content

Commit

Permalink
Merge pull request #199 from foomo/v0.18.x
Browse files Browse the repository at this point in the history
Release v0.18.x
  • Loading branch information
franklinkim authored Jun 28, 2024
2 parents 2d2e450 + 04c4d55 commit 8d300e2
Show file tree
Hide file tree
Showing 66 changed files with 1,117 additions and 1,257 deletions.
26 changes: 15 additions & 11 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2

updates:
- package-ecosystem: "github-actions"
directory: "/"
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/"
interval: weekly

- package-ecosystem: gomod
directory: '/'
schedule:
interval: "weekly"
interval: weekly
groups:
gomod-security:
applies-to: security-updates
patterns: ['*']
gomod-update:
applies-to: version-updates
patterns: ['*']
13 changes: 7 additions & 6 deletions .github/workflows/test.yml → .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
name: Test Branch
name: PR check

on:
push:
branches: [ main ]
pull_request:
merge_group:
workflow_dispatch:

concurrency:
Expand All @@ -16,20 +17,20 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version: 'stable'
go-version-file: 'go.mod'

- uses: gotesttools/gotestfmt-action@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}

- uses: golangci/golangci-lint-action@v3
- uses: golangci/golangci-lint-action@v4
with:
version: latest
args: --timeout=5m

- run: make test
- name: Run tests
run: make test

- uses: coverallsapp/github-action@v2
with:
Expand Down
11 changes: 5 additions & 6 deletions .github/workflows/release.yml → .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- run: git fetch --force --tags
- name: Unshallow
run: git fetch --prune --unshallow

- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version: 'stable'
go-version-file: go.mod

- uses: goreleaser/goreleaser-action@v4
- uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: release --clean
Expand Down
245 changes: 192 additions & 53 deletions .golangci.yml

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
project_name: keel

release:
github:
owner: foomo
name: keel
prerelease: auto

builds:
- skip: true

archives:
- format: tar.gz
format_overrides:
- goos: windows
format: zip
files:
- LICENSE
- README.md

changelog:
use: github-native
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ doc:
.PHONY: test
## Run tests
test:
@go test -coverprofile=coverage.out -race -json ./... | gotestfmt
@go test -p 1 -coverprofile=coverage.out -race -json ./... | gotestfmt

.PHONY: lint
## Run linter
Expand Down
2 changes: 1 addition & 1 deletion config/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package config
import (
"github.com/pkg/errors"
"github.com/spf13/viper"
_ "github.com/spf13/viper/remote"
_ "github.com/spf13/viper/remote" // required import
)

var remotes []struct {
Expand Down
4 changes: 2 additions & 2 deletions config/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func WatchBool(ctx context.Context, fn func() bool, callback func(bool)) {
func WatchTime(ctx context.Context, fn func() time.Time, callback func(time.Time)) {
current := fn()
watch(ctx, func() {
if value := fn(); value != current {
if value := fn(); !value.Equal(current) {
current = value
callback(current)
}
Expand Down Expand Up @@ -102,7 +102,7 @@ func WatchBoolChan(ctx context.Context, fn func() bool, ch chan bool) {
func WatchTimeChan(ctx context.Context, fn func() time.Time, ch chan time.Time) {
current := fn()
watch(ctx, func() {
if value := fn(); value != current {
if value := fn(); !value.Equal(current) {
current = value
ch <- current
}
Expand Down
1 change: 1 addition & 0 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ import (

var (
ErrServerNotRunning = errors.New("server not running")
ErrServerShutdown = errors.New("server is shutting down")
)
7 changes: 4 additions & 3 deletions errors/wrappederror_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
keelerrors "github.com/foomo/keel/errors"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func ExampleNewWrappedError() {
Expand Down Expand Up @@ -63,13 +64,13 @@ func Test_wrappedError_Error(t *testing.T) {
parentErr := errors.New("parent")
childErr := errors.New("child")
wrappedErr := keelerrors.NewWrappedError(parentErr, childErr)
assert.Equal(t, wrappedErr.Error(), "parent: child")
assert.Equal(t, "parent: child", wrappedErr.Error())
}

func Test_wrappedError_Is(t *testing.T) {
parentErr := errors.New("parent")
childErr := errors.New("child")
wrappedErr := keelerrors.NewWrappedError(parentErr, childErr)
assert.ErrorIs(t, wrappedErr, parentErr)
assert.ErrorIs(t, wrappedErr, childErr)
require.ErrorIs(t, wrappedErr, parentErr)
require.ErrorIs(t, wrappedErr, childErr)
}
126 changes: 98 additions & 28 deletions examples/graceful/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,128 @@ package main
import (
"context"
"net/http"
"sync"
"syscall"
"time"

"github.com/foomo/keel/interfaces"
"github.com/foomo/keel/service"
"go.uber.org/zap"

"github.com/foomo/keel"
"github.com/foomo/keel/log"
)

func main() {
service.DefaultHTTPHealthzAddr = "localhost:9400"

l := zap.NewExample().Named("root")

go func() {
c := make(chan bool, 1)
time.Sleep(2 * time.Second)

l.Info("1. starting checks")
go func() {
c <- true
for {
call(l.Named("http"), "http://localhost:8080")
call(l.Named("readiness"), "http://localhost:9400/healthz/readiness")
time.Sleep(time.Second)
}
}()
<-c
close(c)

l.Info("2. sleeping for 5 seconds")
time.Sleep(5 * time.Second)

l.Info("3. sending shutdown signal")
if err := syscall.Kill(syscall.Getpid(), syscall.SIGTERM); err != nil {
l.Fatal(err.Error())
}
}()

svr := keel.NewServer(
keel.WithHTTPZapService(true),
keel.WithHTTPViperService(true),
keel.WithHTTPPrometheusService(true),
keel.WithLogger(l.Named("server")),
keel.WithHTTPHealthzService(true),
)

l := svr.Logger()

go waitGroup(svr.CancelContext(), l.With(log.FServiceName("waitGroup")))

// create demo service
svs := http.NewServeMux()
svs.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("OK"))
})

svr.AddService(
service.NewHTTP(l, "demo", "localhost:8080", svs),
service.NewHTTP(l, "http", "localhost:8080", svs),
)

svr.AddCloser(interfaces.CloserFunc(func(ctx context.Context) error {
l := l.Named("closer")
l.Info("closing stuff")
time.Sleep(3 * time.Second)
l.Info("done closing stuff")
return nil
}))

svr.Run()
}
l.Info("done")

func waitGroup(ctx context.Context, l *zap.Logger) {
var wg sync.WaitGroup
// Output:
// {"level":"info","logger":"root.server","msg":"starting keel server"}
// {"level":"info","logger":"root.server","msg":"starting keel service","keel_service_type":"http","keel_service_name":"healthz","net_host_ip":"localhost","net_host_port":"9400"}
// {"level":"info","logger":"root","msg":"starting keel service","keel_service_type":"http","keel_service_name":"http","net_host_ip":"localhost","net_host_port":"8080"}
// {"level":"info","logger":"root","msg":"1. starting checks"}
// {"level":"info","logger":"root","msg":"2. sleeping for 5 seconds"}
// {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200}
// {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200}
// {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200}
// {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200}
// {"level":"info","logger":"root.http","msg":"ok","url":"http://localhost:8080","status":200}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":200}
// {"level":"info","logger":"root","msg":"3. sending shutdown signal"}
// {"level":"info","logger":"root.server","msg":"keel graceful shutdown","graceful_period":"30s"}
// {"level":"info","logger":"root.server","msg":"keel graceful shutdown: closers"}
// {"level":"info","logger":"root","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"http"}
// {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"*service.HTTP"}
// {"level":"info","logger":"root.closer","msg":"closing stuff"}
// {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"}
// {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503}
// {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"}
// {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503}
// {"level":"error","logger":"root.http","msg":"failed to send request","url":"http://localhost:8080","error":"Get \"http://localhost:8080\": dial tcp [::1]:8080: connect: connection refused"}
// {"level":"debug","logger":"root.server","msg":"healthz probe failed","error_type":"*errors.errorString","error_message":"service not running","http_target":"/healthz/readiness"}
// {"level":"info","logger":"root.readiness","msg":"ok","url":"http://localhost:9400/healthz/readiness","status":503}
// {"level":"info","logger":"root.closer","msg":"done closing stuff"}
// {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"interfaces.CloserFunc"}
// {"level":"info","logger":"root.server","msg":"stopping keel service","keel_service_type":"http","keel_service_name":"healthz"}
// {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"*service.HTTP"}
// {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"noop.TracerProvider"}
// {"level":"debug","logger":"root.server","msg":"keel graceful shutdown: closer closed","name":"noop.MeterProvider"}
// {"level":"info","logger":"root.server","msg":"keel graceful shutdown: complete"}
// {"level":"info","logger":"root.server","msg":"keel server stopped"}
// {"level":"info","logger":"root","msg":"done"}
}

wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
l.Info("Break the loop")
return
case <-time.After(3 * time.Second):
l.Info("Hello in a loop")
}
}
}()
func call(l *zap.Logger, url string) {
l = l.With(zap.String("url", url))

wg.Wait()
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
l.With(zap.Error(err)).Error("failed to create request")
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
l.With(zap.Error(err)).Error("failed to send request")
return
}
l.Info("ok", zap.Int("status", resp.StatusCode))
}
6 changes: 3 additions & 3 deletions examples/healthz/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import (
// See k8s for probe documentation
// https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#types-of-probe
func main() {
service.DefaultHTTPHealthzAddr = "localhost:9400"

// you can override the below config by settings env vars
_ = os.Setenv("SERVICE_HEALTHZ_ENABLED", "true")

svr := keel.NewServer(
keel.WithHTTPZapService(true),
keel.WithHTTPViperService(true),
// allows you to use probes for health checks in cluster:
// GET :9400/healthz
// GET :9400/healthz/readiness
Expand Down Expand Up @@ -65,7 +65,7 @@ func main() {
select {
case <-time.After(10 * time.Second):
l.Info("initialization done")
case <-svr.CancelContext().Done():
case <-svr.ShutdownContext().Done():
l.Info("initialization canceled")
}

Expand Down
9 changes: 6 additions & 3 deletions examples/persistence/mongo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ func main() {
l := svr.Logger()

cDateTime := &store.DateTimeCodec{}
rb := bson.NewRegistryBuilder()
rb.RegisterCodec(store.TDateTime, cDateTime)
rb := bson.NewRegistry()
rb.RegisterTypeEncoder(store.TDateTime, cDateTime)
rb.RegisterTypeDecoder(store.TDateTime, cDateTime)

// create persistor
persistor, err := keelmongo.New(
Expand All @@ -36,7 +37,9 @@ func main() {
// enable telemetry (enabled by default)
keelmongo.WithOtelEnabled(true),
keelmongo.WithClientOptions(
options.Client().SetRegistry(rb.Build()),
func(clientOptions *options.ClientOptions) {
clientOptions.SetRegistry(rb)
},
),
)
// use log must helper to exit on error
Expand Down
Loading

0 comments on commit 8d300e2

Please sign in to comment.