Skip to content
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

[feat] Support periodic refresh of sampling strategies #2188

Merged
merged 2 commits into from
Apr 25, 2020

Conversation

defool
Copy link
Contributor

@defool defool commented Apr 19, 2020

PR for #2186

Signed-off-by: defool defool@foxmail.com

Which problem is this PR solving?

  • Add CLI option to refresh sampling strategies file.

Short description of the changes

  • Add --strategies-reload-interval option for updating strategies periodically.

@defool defool requested a review from a team as a code owner April 19, 2020 11:53
@defool defool force-pushed the master branch 5 times, most recently from 4b44892 to c8195f9 Compare April 19, 2020 15:39
@codecov
Copy link

codecov bot commented Apr 19, 2020

Codecov Report

Merging #2188 into master will increase coverage by 0.01%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2188      +/-   ##
==========================================
+ Coverage   96.14%   96.16%   +0.01%     
==========================================
  Files         219      219              
  Lines       10586    10628      +42     
==========================================
+ Hits        10178    10220      +42     
+ Misses        353      351       -2     
- Partials       55       57       +2     
Impacted Files Coverage Δ
plugin/sampling/strategystore/static/constants.go 100.00% <100.00%> (ø)
plugin/sampling/strategystore/static/options.go 100.00% <100.00%> (ø)
...in/sampling/strategystore/static/strategy_store.go 100.00% <100.00%> (ø)
cmd/query/app/server.go 91.78% <0.00%> (-2.74%) ⬇️
plugin/storage/badger/spanstore/reader.go 96.79% <0.00%> (ø)
...lugin/sampling/strategystore/adaptive/processor.go 100.00% <0.00%> (+0.79%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b99114e...b9ca39b. Read the comment docs.

@yurishkuro yurishkuro changed the title Add API for collector to refresh sampling strategies Support periodic refresh of sampling strategies Apr 19, 2020
Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

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

Thank you for the PR. Note that it does not address #2186 as that one is about an external API (e.g. JSON endpoint). But periodic reloading is a good feature.

if err != nil {
return ss, err
}
if s, ok := ss.(strategystore.StrategyUpdater); f.options.ReloadInterval > 0 && ok {
Copy link
Member

Choose a reason for hiding this comment

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

strategystore.StrategyUpdater interface is unnecessary at this time. This factory is already coupled with static storage, so it already knows that it supports Update method.

Also, it is better to implement the timer loop inside that storage, not in the factory.

for {
select {
case <-ticker.C:
if currBytes, err := ioutil.ReadFile(filepath.Clean(filePath)); err == nil {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if currBytes, err := ioutil.ReadFile(filepath.Clean(filePath)); err == nil {
currBytes, err := ioutil.ReadFile(filepath.Clean(filePath))
if err != nil {
log
continue
}


func TestAutoReload(t *testing.T) {
// copy from fixtures/strategies.json
srcFile, dstFile := "fixtures/strategies.json", "fixtures/strategies_for_reload.json"
Copy link
Member

Choose a reason for hiding this comment

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

either use ioutil.TempFile() or add strategies_for_reload.json to fixtures/.gitignore


// Test reading strategies from a file
//ctx, canf := context.WithCancel(context.Background())
//defer canf()
Copy link
Member

Choose a reason for hiding this comment

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

remove?

}

// AddFlags adds flags for Options
func AddFlags(flagSet *flag.FlagSet) {
flagSet.String(samplingStrategiesFile, "", "The path for the sampling strategies file in JSON format. See sampling documentation to see format of the file")
flagSet.Duration(samplingStrategiesReloadInterval, 0, "Reload interval to check and reload sampling strategies file. Zero value means no checks (default 0s)")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
flagSet.Duration(samplingStrategiesReloadInterval, 0, "Reload interval to check and reload sampling strategies file. Zero value means no checks (default 0s)")
flagSet.Duration(samplingStrategiesReloadInterval, 0, "Reload interval to check and reload sampling strategies file. Zero value means no reloading")

the default value is printed automatically

@@ -23,3 +23,9 @@ type StrategyStore interface {
// GetSamplingStrategy retrieves the sampling strategy for the specified service.
GetSamplingStrategy(serviceName string) (*sampling.SamplingStrategyResponse, error)
}

// StrategyUpdater updates sampling strategies.
Copy link
Member

Choose a reason for hiding this comment

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

not needed, see comments in the factory


f := NewFactory()
v, command := config.Viperize(f.AddFlags)
_ = command.ParseFlags([]string{"--sampling.strategies-file=" + dstFile, "--sampling.strategies-reload-interval=50ms"})
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
_ = command.ParseFlags([]string{"--sampling.strategies-file=" + dstFile, "--sampling.strategies-reload-interval=50ms"})
_ = command.ParseFlags([]string{
"--sampling.strategies-file=" + dstFile,
"--sampling.strategies-reload-interval=50ms",
})

require.NoError(t, err)

// wait for reload
time.Sleep(time.Millisecond * 50 * 2)
Copy link
Member

Choose a reason for hiding this comment

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

Sleeps are not reliable in CI. Please use a loop

for i:=0; i < 100; i++ { // wait up to 1sec
    if condition {
        break
    }
    time.Sleep(10ms)
}
assert

//ctx, canf := context.WithCancel(context.Background())
//defer canf()

store, err := f.CreateStrategyStore()
Copy link
Member

Choose a reason for hiding this comment

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

This leaks a goroutine. There needs to be a way to shut down cleanly.

Copy link
Member

Choose a reason for hiding this comment

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

if we move reloading loop into storage, the test should move there as well (factory should only test parsing the options)

@@ -79,7 +78,7 @@ func TestPerOperationSamplingStrategies(t *testing.T) {
os := s.OperationSampling
assert.EqualValues(t, os.DefaultSamplingProbability, 0.8)
require.Len(t, os.PerOperationStrategies, 4)
fmt.Println(os)
//fmt.Println(os)
Copy link
Member

Choose a reason for hiding this comment

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

remove altogether

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for suggestions, I will remove it in the later revision.

@yurishkuro yurishkuro changed the title Support periodic refresh of sampling strategies [feat] Support periodic refresh of sampling strategies Apr 19, 2020
@yurishkuro yurishkuro added the changelog:new-feature Change that should be called out as new feature in CHANGELOG label Apr 19, 2020
@defool defool force-pushed the master branch 3 times, most recently from a53bb83 to 8353fa6 Compare April 20, 2020 12:53
Signed-off-by: defool <defool@foxmail.com>
}

// StopUpdateStrategy stops updating the strategy
func (h *strategyStore) StopUpdateStrategy() {
Copy link
Member

Choose a reason for hiding this comment

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

usually we call this Close()

return fmt.Errorf("failed to unmarshal strategies: %w", err)
}
h.parseStrategies(&strategies)
h.logger.Info("Updated strategy:" + string(bytes))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
h.logger.Info("Updated strategy:" + string(bytes))
h.logger.Info("Updated sampling strategies:" + string(bytes))

require.NoError(t, err)

// wait for reload
time.Sleep(interval * 2)
Copy link
Member

Choose a reason for hiding this comment

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

as I mentioned, we cannot rely on a single sleep, it makes the tests unstable due to unpredictable pauses in the CI. Use a longer loop with short checks, in most cases it will exit quickly.

os.Remove(dstFile)

// wait for delete and update failed
time.Sleep(interval * 2)
Copy link
Member

Choose a reason for hiding this comment

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

what is this testing (and how)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The purpose is to increase the test code coverage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is there any other comment on this PR?

Copy link
Member

Choose a reason for hiding this comment

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

Instead of checking the error conditions via timer updates, I recommend refactoring the logic under case <-ticker.C into a helper function reloadStrategiesFile and unit-testing that function with the desired edge cases.

Signed-off-by: defool <defool@foxmail.com>
case <-ticker.C:
currBytes, err := ioutil.ReadFile(filepath.Clean(filePath))
if err != nil {
h.logger.Error("ReadFile failed", zap.Error(err))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
h.logger.Error("ReadFile failed", zap.Error(err))
h.logger.Error("failed to load sampling strategies", zap.String("file", filePath), zap.Error(err))
continue

continue
}
if err = h.updateSamplingStrategy(currBytes); err != nil {
h.logger.Error("UpdateSamplingStrategy failed", zap.Error(err))
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
h.logger.Error("UpdateSamplingStrategy failed", zap.Error(err))
h.logger.Error("failed to update sampling strategies from file", zap.Error(err))

func (h *strategyStore) updateSamplingStrategy(bytes []byte) error {
var strategies strategies
if err := json.Unmarshal(bytes, &strategies); err != nil {
return fmt.Errorf("failed to unmarshal strategies: %w", err)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return fmt.Errorf("failed to unmarshal strategies: %w", err)
return fmt.Errorf("failed to unmarshal sampling strategies: %w", err)

os.Remove(dstFile)

// wait for delete and update failed
time.Sleep(interval * 2)
Copy link
Member

Choose a reason for hiding this comment

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

Instead of checking the error conditions via timer updates, I recommend refactoring the logic under case <-ticker.C into a helper function reloadStrategiesFile and unit-testing that function with the desired edge cases.

@yurishkuro yurishkuro merged commit b687b1b into jaegertracing:master Apr 25, 2020
yurishkuro pushed a commit to yurishkuro/jaeger that referenced this pull request Apr 25, 2020
Signed-off-by: Yuri Shkuro <ys@uber.com>
yurishkuro added a commit that referenced this pull request Apr 25, 2020
Signed-off-by: Yuri Shkuro <ys@uber.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog:new-feature Change that should be called out as new feature in CHANGELOG
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants