Skip to content

feat: Add blocking timeout in polling config manager. #236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from

Conversation

yasirfolio3
Copy link
Contributor

@yasirfolio3 yasirfolio3 commented Jan 27, 2020

Summary

This introduces blocking timeout in PollingConfigManager. Config Manager will block any calling go-routine until the config is available or the timeout occurs.

@msohailhussain
Copy link
Contributor

converage is decreased, @yasirfolio3 let's discuss how coverage can be increased.

@msohailhussain msohailhussain marked this pull request as ready for review January 29, 2020 22:12
@msohailhussain msohailhussain requested a review from a team as a code owner January 29, 2020 22:12

start := time.Now()
expectedExecutionTime := start.Add(blockingTimeout)
_, _ = configManager.GetConfig()
Copy link
Contributor

Choose a reason for hiding this comment

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

please add comment, blocking api for specified time.

@yasirfolio3 yasirfolio3 reopened this Jan 30, 2020
Copy link
Contributor

@mjc1283 mjc1283 left a comment

Choose a reason for hiding this comment

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

Nit in PR description:

Config Manager will block the main thread until the config is available or the timeout occurs

What is the "main thread"? It will block any calling goroutine, right?

@@ -36,6 +36,9 @@ import (
// DefaultPollingInterval sets default interval for polling manager
const DefaultPollingInterval = 5 * time.Minute // default to 5 minutes for polling

// DefaultBlockingTimeout sets timeout to block the config call until config has been initialized
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// DefaultBlockingTimeout sets timeout to block the config call until config has been initialized
// DefaultBlockingTimeout is the default timeout for blocking in the GetConfig method until a config has been initialized

import "time"

// IsChannelClosed will check if the given channel is closed
func IsChannelClosed(ch chan struct{}) bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: can we use read-only channel type <-chan struct{}? And also below in WaitForChannelToCloseOrTimeout?

Comment on lines 153 to 169
func TestGetConfigForPollingConfigManagerWaitsForTimeoutForInvalidDatafile(t *testing.T) {
blockingTimeout := 50 * time.Millisecond
mockDatafile := []byte("NOT-VALID")
mockRequester := new(MockRequester)
mockRequester.On("Get", []utils.Header(nil)).Return(mockDatafile, http.Header{}, http.StatusOK, nil)

sdkKey := "test_sdk_key"

configManager := NewPollingProjectConfigManager(sdkKey, WithRequester(mockRequester), WithBlockingTimeout(blockingTimeout))
mockRequester.AssertExpectations(t)

start := time.Now()
expectedExecutionTime := start.Add(blockingTimeout)
_, _ = configManager.GetConfig()
actualExecutionTime := start.Add(time.Since(start))
assert.WithinDuration(t, expectedExecutionTime, actualExecutionTime, 10*time.Millisecond)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This test case and the others with 50ms blocking timeout seem to have the potential to be flaky, and will run very slowly. I will think about other ways to test this behavior - @pawels-optimizely @mikeng13 @mikecdavis any ideas?

@yasirfolio3
Copy link
Contributor Author

Nit in PR description:

Config Manager will block the main thread until the config is available or the timeout occurs

What is the "main thread"? It will block any calling goroutine, right?

correct, thanks for the correction.

@pawels-optimizely pawels-optimizely self-requested a review January 30, 2020 22:45
Copy link
Contributor

@pawels-optimizely pawels-optimizely left a comment

Choose a reason for hiding this comment

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

config.NewAsyncPollingProjectConfigManager(sdkKey, config.WithPollingInterval(1*time.Minute)) does not work at all, while config.NewPollingProjectConfigManager(sdkKey, config.WithPollingInterval(1*time.Minute)) works with no problem

// blocking api for specified time.
_, _ = configManager.GetConfig()
actualExecutionTime := start.Add(time.Since(start))
assert.WithinDuration(t, expectedExecutionTime, actualExecutionTime, 10*time.Millisecond)
Copy link
Contributor

Choose a reason for hiding this comment

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

@yasirfolio3 @msohailhussain Following up on my earlier comment.

To limit flakiness I suggest we remove this assert.WithinDuration. Instead, we can implement a timeout on the total execution time of this test case, failing when it exceeds a pretty large duration, like 1-2 seconds. This lets us be resilient to varying execution time of GetConfig, while still ensuring that our test fails when the implementation of the timeout inside GetConfig is broken.

@@ -146,6 +150,129 @@ func TestNewAsyncPollingProjectConfigManagerWithNullDatafile(t *testing.T) {
mockRequester.AssertExpectations(t)
}

func TestGetConfigForPollingConfigManagerWaitsForTimeoutForInvalidDatafile(t *testing.T) {
blockingTimeout := 50 * time.Millisecond
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest reducing this to 1 millisecond, combined with my other suggestion, there is no need for this to be so high.

@mikeproeng37 mikeproeng37 deleted the yasir/blocking-timeout branch March 6, 2020 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants