-
Notifications
You must be signed in to change notification settings - Fork 813
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
Define dynamic config and integrate in service bootstrap #543
Conversation
I thought we agreed on the design that doesn't use lookups to config from the application code. Instead we only use structures to configure any application logic. |
@mfateev Similar to latest commit? Or ware you implying dependency injection? |
a6111d9
to
1118834
Compare
} | ||
|
||
// GetIntPropertyWithTaskList gets property with taskList filter and asserts that it's an integer | ||
func (c *Collection) GetIntPropertyWithTaskList(key Key, defaultVal int) func(string) int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would make this package non Cadence specific. So this method would be something like:
func (c *Collection) GetIntPropertyWithStringFilter(key Key, defaultValue int, filter Filter) func(string) int {
return func(filterValue string) int {
filters := make(map[Filter]interface{})
filters[filter] = filterValue
val, err := c.client.GetValueWithFilters(key, filters)
if err != nil {
return defaultVal
}
return val.(int)
}
}
Then the code that uses it would make it task list specific. If the task list appears as filter in a lot of places the
then the following function (outside of this package) can be created:
func GetIntPropertyWithTaskListFilter(c *Collection, key Key, defaultValue int) func(string) int {
return c.GetIntPropertyWithString(key, defaultValue, TaskListName)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the benefit of a public generic function? Makes sense as a private method if we have public methods for both task list and domain name.
Also all these methods are for Cadence, what is a non-Cadence use case for this?
return val.(int) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each of Get methods repeats the same code snippet. What about:
func (c *Collection) GetProperty(key Key, defaultVal interface{}) func() interface{} {
return func() int {
val, err := c.client.GetValue(key)
if err != nil {
return defaultVal
}
return val
}
}
Then Get methods become like:
func (c *Collection) GetFloat64Property(key Key, defaultVal float64) func() float64 {
return func() float64 {
return GetProperty(key, defaultVal)().(float64)
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With generic functions here and the previous filter one as well, there is an extra cast for converting defaultValue from empty interface to the corresponding type. I wrote some benchmark tests to compare the two and the previous non-generic approach is about 20% faster (260 versus 210 ns). I would favor performance here over reducing duplication since this function could be called quite frequently based on where it's being used. Let me know what you think. Will push my commit with benchmark test so you can take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
go test ./common/service/dynamicconfig/ -bench=.
goos: darwin
goarch: amd64
pkg: github.com/uber/cadence/common/service/dynamicconfig
BenchmarkGetIntProperty-8 5000000 279 ns/op
BenchmarkGetIntPropertyOld-8 10000000 219 ns/op
PASS
ok github.com/uber/cadence/common/service/dynamicconfig 4.122s
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
// THE SOFTWARE. | ||
|
||
package dynamicconfig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would break this into two packages dynamicconfig and cadenceconfig. The content of this file doesn't belong to generic dynamicconfig one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, not sure what the non-cadence usage is. The dynamic config is solely for cadence.
@@ -195,7 +196,7 @@ func (s *matchingEngineSuite) TestPollForDecisionTasksEmptyResult() { | |||
|
|||
func (s *matchingEngineSuite) PollForTasksEmptyResultTest(taskType int) { | |||
s.matchingEngine.config.RangeSize = 2 // to test that range is not updated without tasks | |||
s.matchingEngine.config.LongPollExpirationInterval = 10 * time.Millisecond | |||
s.matchingEngine.config.LongPollExpirationInterval = func() time.Duration { return 10 * time.Millisecond } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be introduce small helper method?
s.matchingEngine.config.LongPollExpirationInterval = DurationConfigMillis(10)
} | ||
|
||
// GetIntProperty gets property and asserts that it's an integer | ||
func (c *Collection) GetIntProperty(key Key, defaultVal int) func() int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename defaultVal to defaultValue in all methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure but why? Go usually advocates for short variable names as opposed to Java eg. https://talks.golang.org/2014/names.slide#6
type Key int | ||
|
||
func (k Key) String() string { | ||
keys := []string{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will create an array variable every time this method is called.
I think a simple switch case clause is easier to understand and more performant.
switch k {
case unknownKey:
return "unknownKey"
case MinTaskThrottlingBurstSize:
return "minTaskThrottlingBurstSize"
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved it out so array variable is not created everytime.
service/matching/taskListManager.go
Outdated
@@ -138,7 +138,9 @@ func newTaskListManager( | |||
e *matchingEngineImpl, taskList *taskListID, taskListKind *s.TaskListKind, config *Config, | |||
) taskListManager { | |||
dPtr := _defaultTaskDispatchRPS | |||
rl := newRateLimiter(&dPtr, _defaultTaskDispatchRPSTTL, config.MinTaskThrottlingBurstSize) | |||
rl := newRateLimiter( | |||
&dPtr, _defaultTaskDispatchRPSTTL, config.MinTaskThrottlingBurstSize(taskList.taskListName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everywhere config is read now needs to know what kind of filters need to be passed in. Can we just have a config object per entity type so all that semantics can be in a single place?
Basically use the exact same config mechanism and have a closure which remembers the name of tasklist when the closure was created. Then the above code will look like:
tasklistMgrConfig.MinTaskThrottlingBurstSize()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Setting up dynamic config and enable for a few config parameters.