Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

Commit

Permalink
fix: fix graceful shutdown in sdk (#6234)
Browse files Browse the repository at this point in the history
* fixed graceful shutdown handling

Signed-off-by: warber <bernd.warmuth@dynatrace.com>

* added exmaple

Signed-off-by: warber <bernd.warmuth@dynatrace.com>

* updated used go-sdk versions in remediation service and webhook service

Signed-off-by: warber <bernd.warmuth@dynatrace.com>
  • Loading branch information
warber committed Dec 1, 2021
1 parent a1a58e2 commit a8db696
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 49 deletions.
48 changes: 48 additions & 0 deletions go-sdk/example/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"bytes"
"github.com/keptn/go-utils/pkg/lib/v0_2_0"
"github.com/keptn/keptn/go-sdk/pkg/sdk"
"html/template"
)

type GreetingsHandler struct {
}

type GreetingTriggeredData struct {
v0_2_0.EventData
Text string `json:"text"`
}

type GreetingFinishedData struct {
v0_2_0.EventData
GreetMessage string `json:"greetMessage"`
}

func NewGreetingsHandler() *GreetingsHandler {
return &GreetingsHandler{}
}

func (g *GreetingsHandler) Execute(k sdk.IKeptn, event sdk.KeptnEvent) (interface{}, *sdk.Error) {
greetingsTriggeredData := &GreetingTriggeredData{}
if err := v0_2_0.Decode(event.Data, greetingsTriggeredData); err != nil {
return nil, &sdk.Error{Err: err, StatusType: v0_2_0.StatusErrored, ResultType: v0_2_0.ResultFailed, Message: "Could not decode input event data"}
}
name := struct{ Name string }{"Keptn"}

tmpl, err := template.New("").Parse(greetingsTriggeredData.Text)
if err != nil {
return nil, &sdk.Error{Err: err, StatusType: v0_2_0.StatusErrored, ResultType: v0_2_0.ResultFailed, Message: "Could not parse greeting message"}
}

var greetMessage bytes.Buffer
if err = tmpl.Execute(&greetMessage, name); err != nil {
return nil, &sdk.Error{Err: err, StatusType: v0_2_0.StatusErrored, ResultType: v0_2_0.ResultFailed, Message: "Could not parse process greeting message"}
}
finishedEventData := GreetingFinishedData{
EventData: greetingsTriggeredData.EventData,
GreetMessage: greetMessage.String(),
}
return finishedEventData, nil
}
40 changes: 40 additions & 0 deletions go-sdk/example/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"encoding/json"
cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/keptn/go-utils/pkg/api/models"
keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0"
"github.com/keptn/keptn/go-sdk/pkg/sdk"
"github.com/stretchr/testify/require"
"io/ioutil"
"log"
"testing"
)

func Test_Handler(t *testing.T) {
fakeKeptn := sdk.NewFakeKeptn("test-greeting-svc")
fakeKeptn.AddTaskHandler(greetingsTriggeredEventType, NewGreetingsHandler())
fakeKeptn.Start()
fakeKeptn.NewEvent(newNewGreetingTriggeredEvent("test-assets/events/greeting.triggered-0.json"))

require.Equal(t, 2, len(fakeKeptn.GetEventSender().SentEvents))
require.Equal(t, keptnv2.GetStartedEventType("greeting"), fakeKeptn.GetEventSender().SentEvents[0].Type())
require.Equal(t, keptnv2.GetFinishedEventType("greeting"), fakeKeptn.GetEventSender().SentEvents[1].Type())

finishedEvent, _ := keptnv2.ToKeptnEvent(fakeKeptn.GetEventSender().SentEvents[1])
greetingFinishedData := GreetingFinishedData{}
finishedEvent.DataAs(&greetingFinishedData)
require.Equal(t, "Hi, my name is Keptn", greetingFinishedData.GreetMessage)
}

func newNewGreetingTriggeredEvent(filename string) cloudevents.Event {
content, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
event := models.KeptnContextExtendedCE{}
err = json.Unmarshal(content, &event)
_ = err
return keptnv2.ToCloudEvent(event)
}
18 changes: 18 additions & 0 deletions go-sdk/example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"github.com/keptn/keptn/go-sdk/pkg/sdk"
"log"
)

const greetingsTriggeredEventType = "sh.keptn.event.greeting.triggered"
const serviceName = "greetings-service"

func main() {
log.Fatal(sdk.NewKeptn(
serviceName,
sdk.WithTaskHandler(
greetingsTriggeredEventType,
NewGreetingsHandler()),
).Start())
}
15 changes: 15 additions & 0 deletions go-sdk/example/test-assets/events/greeting.triggered-0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"type": "sh.keptn.event.greeting.triggered",
"specversion": "1.0",
"source": "test",
"id": "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79d",
"time": "2019-06-07T07:02:15.64489Z",
"contenttype": "application/json",
"shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc50f",
"data": {
"project": "my-project",
"service": "my-service",
"stage": "ms-stage",
"text": "Hi, my name is {{ .Name }}"
}
}
68 changes: 32 additions & 36 deletions go-sdk/pkg/sdk/keptn.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ type gracefulShutdownKeyType struct{}

var gracefulShutdownKey = gracefulShutdownKeyType{}

type wgInterface interface {
Add(delta int)
Done()
Wait()
}

type nopWG struct {
// --
}

func (w *nopWG) Add(delta int) {
// --
}
func (w *nopWG) Done() {
// --
}
func (w *nopWG) Wait() {
// --
}

type Error struct {
StatusType keptnv2.StatusType
ResultType keptnv2.ResultType
Expand Down Expand Up @@ -111,7 +131,7 @@ type Keptn struct {
syncProcessing bool
automaticEventResponse bool
gracefulShutdown bool
recievingEvent interface{}
receivingEvent interface{}
}

// NewKeptn creates a new Keptn
Expand All @@ -136,18 +156,9 @@ func NewKeptn(source string, opts ...KeptnOption) *Keptn {
}

func (k *Keptn) Start() error {
ctx := getGracefulContext()
ctx := getContext(k.gracefulShutdown)
err := k.eventReceiver.StartReceiver(ctx, k.gotEvent)
if k.gracefulShutdown {
//this is gonna change
val := ctx.Value(gracefulShutdownKey)
if val != nil {

if wg, ok := val.(*sync.WaitGroup); ok {
wg.Wait()
}
}
}
ctx.Value(gracefulShutdownKey).(wgInterface).Wait()
return err
}

Expand Down Expand Up @@ -186,28 +197,10 @@ func (k *Keptn) gotEvent(ctx context.Context, event cloudevents.Event) {
log.Errorf("event with event type %s is no valid keptn task event type", event.Type())
return
}

var val interface{} = nil
if k.gracefulShutdown {
val = ctx.Value(gracefulShutdownKey)
}
if val != nil {
if wg, ok := val.(*sync.WaitGroup); ok {
wg.Add(1)
}
}

ctx.Value(gracefulShutdownKey).(wgInterface).Add(1)
k.runEventTaskAction(func() {
{
defer func() {
if val == nil {
return
}
if wg, ok := val.(*sync.WaitGroup); ok {
wg.Done()
}
}()

defer ctx.Value(gracefulShutdownKey).(wgInterface).Done()
if handler, ok := k.taskRegistry.Contains(event.Type()); ok {
keptnEvent := &KeptnEvent{}
if err := keptnv2.Decode(&event, keptnEvent); err != nil {
Expand Down Expand Up @@ -421,12 +414,15 @@ func (k *Keptn) createErrorFinishedEventForTriggeredEvent(event cloudevents.Even
return &c, nil
}

// getGracefulContext returns a context with cancel and a wait group to sync before shutdown
func getGracefulContext() context.Context {

func getContext(graceful bool) context.Context {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
wg := &sync.WaitGroup{}
var wg wgInterface
if graceful {
wg = &sync.WaitGroup{}
} else {
wg = &nopWG{}
}
ctx, cancel := context.WithCancel(cloudevents.WithEncodingStructured(context.WithValue(context.Background(), gracefulShutdownKey, wg)))

go func() {
Expand Down
6 changes: 5 additions & 1 deletion go-sdk/pkg/sdk/keptn_fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (f *FakeKeptn) GetResourceHandler() ResourceHandler {

func (f *FakeKeptn) NewEvent(event cloudevents.Event) {
testReceiver := f.Keptn.eventReceiver.(*TestReceiver)
testReceiver.NewEvent(context.Background(), event)
testReceiver.NewEvent(context.WithValue(context.Background(), gracefulShutdownKey, &nopWG{}), event)
}

func (f *FakeKeptn) GetEventSender() *TestSender {
Expand Down Expand Up @@ -73,6 +73,7 @@ func NewFakeKeptn(source string) *FakeKeptn {
taskRegistry: NewTasksMap(),
syncProcessing: true,
automaticEventResponse: true,
gracefulShutdown: false,
},
}
return fakeKeptn
Expand Down Expand Up @@ -130,6 +131,9 @@ func (t *TestReceiver) StartReceiver(ctx context.Context, fn interface{}) error
}

func (t *TestReceiver) NewEvent(ctx context.Context, e cloudevents.Event) {
if ctx.Value(gracefulShutdownKey) == nil {
ctx = context.WithValue(ctx, gracefulShutdownKey, &nopWG{})
}
t.receiverFn.(func(context.Context, event.Event))(ctx, e)
}

Expand Down
10 changes: 4 additions & 6 deletions go-sdk/pkg/sdk/keptn_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sdk

import (
"context"
"fmt"
cloudevents "github.com/cloudevents/sdk-go/v2"
"github.com/cloudevents/sdk-go/v2/event"
Expand Down Expand Up @@ -41,8 +42,7 @@ func Test_WhenReceivingAnEvent_StartedEventAndFinishedEventsAreSent(t *testing.T
}

keptn.Start()
ctx := getGracefulContext()
eventReceiver.NewEvent(ctx, newTestTaskTriggeredEvent())
eventReceiver.NewEvent(context.Background(), newTestTaskTriggeredEvent())

require.Eventuallyf(t, func() bool {
return len(eventSender.SendEventCalls()) == 2
Expand Down Expand Up @@ -89,8 +89,7 @@ func Test_WhenReceivingEvent_OnlyStartedEventIsSent(t *testing.T) {
}

keptn.Start()
ctx := getGracefulContext()
eventReceiver.NewEvent(ctx, newTestTaskTriggeredEvent())
eventReceiver.NewEvent(context.Background(), newTestTaskTriggeredEvent())

require.Eventuallyf(t, func() bool {
fmt.Println(len(eventSender.SendEventCalls()))
Expand Down Expand Up @@ -130,8 +129,7 @@ func Test_WhenReceivingBadEvent_NoEventIsSent(t *testing.T) {
}

keptn.Start()
ctx := getGracefulContext()
eventReceiver.NewEvent(ctx, newTestTaskBadTriggeredEvent())
eventReceiver.NewEvent(context.Background(), newTestTaskBadTriggeredEvent())

require.Eventuallyf(t, func() bool {
fmt.Println(len(eventSender.SendEventCalls()))
Expand Down
2 changes: 1 addition & 1 deletion remediation-service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/cloudevents/sdk-go/v2 v2.5.0
github.com/ghodss/yaml v1.0.0
github.com/keptn/go-utils v0.11.0
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v2 v2.4.0 // indirect
)
4 changes: 2 additions & 2 deletions remediation-service/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/keptn/go-utils v0.11.0 h1:cwr9BDkDQcsURwj9pkkTzTs4M2HDqlgv1mrllPfysxY=
github.com/keptn/go-utils v0.11.0/go.mod h1:wOOwrQxPrKNzEzP7xK58MLikUuQXi/HPvKlOmuS5qMk=
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332 h1:JosruuBfRsO1dC/NicjmCv8IwpVU5vheq74f9y84pfk=
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332/go.mod h1:MuQBrF54qgurj9W592ORBfk875Jk2Zx7ZcJ1iDPyyTs=
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7 h1:yMQxVzxLfx9uHUeZHINq6/q/bU3XvPJPq2nOWrT6S9w=
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7/go.mod h1:MuQBrF54qgurj9W592ORBfk875Jk2Zx7ZcJ1iDPyyTs=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand Down
2 changes: 1 addition & 1 deletion webhook-service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.16
require (
github.com/cloudevents/sdk-go/v2 v2.5.0
github.com/keptn/go-utils v0.11.0
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
Expand Down
4 changes: 2 additions & 2 deletions webhook-service/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/keptn/go-utils v0.11.0 h1:cwr9BDkDQcsURwj9pkkTzTs4M2HDqlgv1mrllPfysxY=
github.com/keptn/go-utils v0.11.0/go.mod h1:wOOwrQxPrKNzEzP7xK58MLikUuQXi/HPvKlOmuS5qMk=
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332 h1:JosruuBfRsO1dC/NicjmCv8IwpVU5vheq74f9y84pfk=
github.com/keptn/keptn/go-sdk v0.0.0-20211123120143-44d21eebc332/go.mod h1:MuQBrF54qgurj9W592ORBfk875Jk2Zx7ZcJ1iDPyyTs=
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7 h1:yMQxVzxLfx9uHUeZHINq6/q/bU3XvPJPq2nOWrT6S9w=
github.com/keptn/keptn/go-sdk v0.0.0-20211130151348-d13abbbd70a7/go.mod h1:MuQBrF54qgurj9W592ORBfk875Jk2Zx7ZcJ1iDPyyTs=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
Expand Down

0 comments on commit a8db696

Please sign in to comment.