Skip to content

Commit ce65de5

Browse files
added ExecutionCtx interface - flexible implementation
1 parent 407c38b commit ce65de5

File tree

8 files changed

+128
-85
lines changed

8 files changed

+128
-85
lines changed

optimizely/client/client.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,17 @@
1818
package client
1919

2020
import (
21-
"context"
2221
"errors"
2322
"fmt"
2423
"runtime/debug"
2524
"strconv"
26-
"sync"
27-
28-
"github.com/optimizely/go-sdk/optimizely/event"
2925

3026
"github.com/optimizely/go-sdk/optimizely"
3127
"github.com/optimizely/go-sdk/optimizely/decision"
3228
"github.com/optimizely/go-sdk/optimizely/entities"
29+
"github.com/optimizely/go-sdk/optimizely/event"
3330
"github.com/optimizely/go-sdk/optimizely/logging"
31+
"github.com/optimizely/go-sdk/optimizely/utils"
3432
)
3533

3634
var logger = logging.GetLogger("Client")
@@ -42,8 +40,7 @@ type OptimizelyClient struct {
4240
eventProcessor event.Processor
4341
isValid bool
4442

45-
cancelFunc context.CancelFunc
46-
wg *sync.WaitGroup
43+
executionCtx utils.ExecutionCtx
4744
}
4845

4946
// IsFeatureEnabled returns true if the feature is enabled for the given user
@@ -281,6 +278,5 @@ func (o *OptimizelyClient) GetProjectConfig() (projectConfig optimizely.ProjectC
281278

282279
// Close closes the Optimizely instance and stops any ongoing tasks from its children components
283280
func (o *OptimizelyClient) Close() {
284-
o.cancelFunc()
285-
o.wg.Wait() // blocking call
281+
o.executionCtx.TerminateAndWait()
286282
}

optimizely/client/factory.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@
1818
package client
1919

2020
import (
21-
"context"
2221
"errors"
23-
"sync"
22+
"github.com/optimizely/go-sdk/optimizely/utils"
2423

2524
"github.com/optimizely/go-sdk/optimizely/event"
2625

@@ -33,7 +32,6 @@ import (
3332

3433
// Options are used to create an instance of the OptimizelyClient with custom configuration
3534
type Options struct {
36-
Context context.Context
3735
ProjectConfigManager optimizely.ProjectConfigManager
3836
DecisionService decision.Service
3937
EventProcessor event.Processor
@@ -78,22 +76,10 @@ func (f OptimizelyFactory) StaticClient() (*OptimizelyClient, error) {
7876
// ClientWithOptions returns a client initialized with the given configuration options
7977
func (f OptimizelyFactory) ClientWithOptions(clientOptions Options) (*OptimizelyClient, error) {
8078

81-
var wg sync.WaitGroup
82-
79+
executionCtx := utils.NewCancelableExecutionCtxExecutionCtx()
8380
client := &OptimizelyClient{
84-
isValid: false,
85-
wg: &wg,
86-
}
87-
88-
var ctx context.Context
89-
if clientOptions.Context != nil {
90-
ctx = clientOptions.Context
91-
} else {
92-
// if no context is provided, we create our own cancellable context and hand it over to the client so the client can shut down its child processes
93-
ctx = context.Background()
94-
var cancel context.CancelFunc
95-
ctx, cancel = context.WithCancel(ctx)
96-
client.cancelFunc = cancel
81+
isValid: false,
82+
executionCtx: executionCtx,
9783
}
9884

9985
notificationCenter := notification.NewNotificationCenter()
@@ -105,7 +91,7 @@ func (f OptimizelyFactory) ClientWithOptions(clientOptions Options) (*Optimizely
10591
options := config.PollingProjectConfigManagerOptions{
10692
Datafile: f.Datafile,
10793
}
108-
client.configManager = config.NewPollingProjectConfigManagerWithOptions(ctx, f.SDKKey, options)
94+
client.configManager = config.NewPollingProjectConfigManagerWithOptions(executionCtx, f.SDKKey, options)
10995
case f.Datafile != nil:
11096
staticConfigManager, _ := config.NewStaticProjectConfigManagerFromPayload(f.Datafile)
11197
client.configManager = staticConfigManager
@@ -122,7 +108,7 @@ func (f OptimizelyFactory) ClientWithOptions(clientOptions Options) (*Optimizely
122108
if clientOptions.EventProcessor != nil {
123109
client.eventProcessor = clientOptions.EventProcessor
124110
} else {
125-
client.eventProcessor = event.NewEventProcessor(ctx, event.DefaultBatchSize, event.DefaultEventQueueSize, event.DefaultEventFlushInterval, &wg)
111+
client.eventProcessor = event.NewEventProcessor(executionCtx, event.DefaultBatchSize, event.DefaultEventQueueSize, event.DefaultEventFlushInterval)
126112
}
127113

128114
client.isValid = true

optimizely/config/polling_manager.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
package config
1919

2020
import (
21-
"context"
2221
"fmt"
2322
"sync"
2423
"time"
2524

2625
"github.com/optimizely/go-sdk/optimizely"
2726
"github.com/optimizely/go-sdk/optimizely/config/datafileprojectconfig"
2827
"github.com/optimizely/go-sdk/optimizely/logging"
28+
"github.com/optimizely/go-sdk/optimizely/utils"
2929
)
3030

3131
const defaultPollingInterval = 5 * time.Minute // default to 5 minutes for polling
@@ -50,7 +50,7 @@ type PollingProjectConfigManager struct {
5050
configLock sync.RWMutex
5151
err error
5252

53-
ctx context.Context // context used for cancellation
53+
exeCtx utils.ExecutionCtx // context used for execution control
5454
}
5555

5656
func (cm *PollingProjectConfigManager) activate(initialPayload []byte, init bool) {
@@ -89,15 +89,15 @@ func (cm *PollingProjectConfigManager) activate(initialPayload []byte, init bool
8989
select {
9090
case <-t.C:
9191
update()
92-
case <-cm.ctx.Done():
92+
case <-cm.exeCtx.GetContext().Done():
9393
cmLogger.Debug("Polling Config Manager Stopped")
9494
return
9595
}
9696
}
9797
}
9898

9999
// NewPollingProjectConfigManagerWithOptions returns new instance of PollingProjectConfigManager with the given options
100-
func NewPollingProjectConfigManagerWithOptions(ctx context.Context, sdkKey string, options PollingProjectConfigManagerOptions) *PollingProjectConfigManager {
100+
func NewPollingProjectConfigManagerWithOptions(exeCtx utils.ExecutionCtx, sdkKey string, options PollingProjectConfigManagerOptions) *PollingProjectConfigManager {
101101

102102
var requester Requester
103103
if options.Requester != nil {
@@ -112,7 +112,7 @@ func NewPollingProjectConfigManagerWithOptions(ctx context.Context, sdkKey strin
112112
pollingInterval = defaultPollingInterval
113113
}
114114

115-
pollingProjectConfigManager := PollingProjectConfigManager{requester: requester, pollingInterval: pollingInterval, ctx: ctx}
115+
pollingProjectConfigManager := PollingProjectConfigManager{requester: requester, pollingInterval: pollingInterval, exeCtx: exeCtx}
116116

117117
pollingProjectConfigManager.activate(options.Datafile, true) // initial poll
118118

@@ -122,9 +122,9 @@ func NewPollingProjectConfigManagerWithOptions(ctx context.Context, sdkKey strin
122122
}
123123

124124
// NewPollingProjectConfigManager returns an instance of the polling config manager with the default configuration
125-
func NewPollingProjectConfigManager(ctx context.Context, sdkKey string) *PollingProjectConfigManager {
125+
func NewPollingProjectConfigManager(exeCtx utils.ExecutionCtx, sdkKey string) *PollingProjectConfigManager {
126126
options := PollingProjectConfigManagerOptions{}
127-
configManager := NewPollingProjectConfigManagerWithOptions(ctx, sdkKey, options)
127+
configManager := NewPollingProjectConfigManagerWithOptions(exeCtx, sdkKey, options)
128128
return configManager
129129
}
130130

optimizely/config/polling_manager_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
package config
1818

1919
import (
20-
"context"
20+
"github.com/optimizely/go-sdk/optimizely/utils"
2121
"testing"
2222

2323
"github.com/stretchr/testify/assert"
@@ -47,7 +47,9 @@ func TestNewPollingProjectConfigManagerWithOptions(t *testing.T) {
4747
options := PollingProjectConfigManagerOptions{
4848
Requester: mockRequester,
4949
}
50-
configManager := NewPollingProjectConfigManagerWithOptions(context.Background(), sdkKey, options)
50+
51+
exeCtx := utils.NewCancelableExecutionCtxExecutionCtx()
52+
configManager := NewPollingProjectConfigManagerWithOptions(exeCtx, sdkKey, options)
5153
mockRequester.AssertExpectations(t)
5254

5355
actual, err := configManager.GetConfig()
@@ -65,7 +67,8 @@ func TestNewPollingProjectConfigManagerWithNull(t *testing.T) {
6567
options := PollingProjectConfigManagerOptions{
6668
Requester: mockRequester,
6769
}
68-
configManager := NewPollingProjectConfigManagerWithOptions(context.Background(), sdkKey, options)
70+
exeCtx := utils.NewCancelableExecutionCtxExecutionCtx()
71+
configManager := NewPollingProjectConfigManagerWithOptions(exeCtx, sdkKey, options)
6972
mockRequester.AssertExpectations(t)
7073

7174
_, err := configManager.GetConfig()

optimizely/event/factory_test.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package event
22

33
import (
4-
"context"
54
"math/rand"
6-
"sync"
75
"testing"
86
"time"
97

108
"github.com/optimizely/go-sdk/optimizely"
11-
129
"github.com/optimizely/go-sdk/optimizely/entities"
10+
"github.com/optimizely/go-sdk/optimizely/utils"
1311
"github.com/stretchr/testify/assert"
1412
)
1513

@@ -90,12 +88,10 @@ func BuildTestConversionEvent() UserEvent {
9088
}
9189

9290
func TestCreateAndSendImpressionEvent(t *testing.T) {
93-
ctx := context.Background()
94-
var wg sync.WaitGroup
9591

9692
impressionUserEvent := BuildTestImpressionEvent()
9793

98-
processor := NewEventProcessor(ctx, 10, 100, 100, &wg)
94+
processor := NewEventProcessor(utils.NewCancelableExecutionCtxExecutionCtx(), 10, 100, 100)
9995

10096
processor.ProcessEvent(impressionUserEvent)
10197

@@ -107,12 +103,10 @@ func TestCreateAndSendImpressionEvent(t *testing.T) {
107103
}
108104

109105
func TestCreateAndSendConversionEvent(t *testing.T) {
110-
ctx := context.Background()
111-
var wg sync.WaitGroup
112106

113107
conversionUserEvent := BuildTestConversionEvent()
114108

115-
processor := NewEventProcessor(ctx, 10, 100, 100, &wg)
109+
processor := NewEventProcessor(utils.NewCancelableExecutionCtxExecutionCtx(), 10, 100, 100)
116110

117111
processor.ProcessEvent(conversionUserEvent)
118112

optimizely/event/processor.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package event
2020
import (
2121
"context"
2222
"errors"
23+
"github.com/optimizely/go-sdk/optimizely/utils"
2324
"sync"
2425
"time"
2526

@@ -56,21 +57,21 @@ const DefaultEventFlushInterval = 30 * time.Second
5657
var pLogger = logging.GetLogger("EventProcessor")
5758

5859
// NewEventProcessor returns a new instance of QueueingEventProcessor with queueSize and flushInterval
59-
func NewEventProcessor(ctx context.Context, batchSize, queueSize int, flushInterval time.Duration, wg *sync.WaitGroup) *QueueingEventProcessor {
60+
func NewEventProcessor(exeCtx utils.ExecutionCtx, batchSize, queueSize int, flushInterval time.Duration) *QueueingEventProcessor {
6061
p := &QueueingEventProcessor{
6162
MaxQueueSize: queueSize,
6263
FlushInterval: flushInterval,
6364
Q: NewInMemoryQueue(queueSize),
6465
EventDispatcher: &HTTPEventDispatcher{},
6566

66-
wg: wg,
67+
wg: exeCtx.GetWaitSync(),
6768
}
6869
p.BatchSize = DefaultBatchSize
6970
if batchSize > 0 {
7071
p.BatchSize = batchSize
7172
}
7273

73-
p.StartTicker(ctx)
74+
p.StartTicker(exeCtx.GetContext())
7475
return p
7576
}
7677

0 commit comments

Comments
 (0)