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

Define dynamic config and integrate in service bootstrap #543

Merged
merged 17 commits into from
Feb 23, 2018
Merged

Conversation

madhuravi
Copy link
Contributor

@madhuravi madhuravi commented Feb 2, 2018

Setting up dynamic config and enable for a few config parameters.

@mfateev
Copy link
Contributor

mfateev commented Feb 2, 2018

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.

@madhuravi
Copy link
Contributor Author

@mfateev Similar to latest commit? Or ware you implying dependency injection?

@coveralls
Copy link

coveralls commented Feb 8, 2018

Coverage Status

Coverage decreased (-0.006%) to 67.513% when pulling 6ec4a4d on dynamic into 095fbd7 on master.

@madhuravi madhuravi force-pushed the dynamic branch 2 times, most recently from a6111d9 to 1118834 Compare February 13, 2018 20:04
}

// GetIntPropertyWithTaskList gets property with taskList filter and asserts that it's an integer
func (c *Collection) GetIntPropertyWithTaskList(key Key, defaultVal int) func(string) int {
Copy link
Contributor

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)
}

Copy link
Contributor Author

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)
}
}

Copy link
Contributor

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) 
      }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea.

Copy link
Contributor Author

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.

Copy link
Contributor Author

@madhuravi madhuravi Feb 16, 2018

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
Copy link
Contributor

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.

Copy link
Contributor Author

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 }
Copy link
Contributor

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 {
Copy link
Contributor

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.

Copy link
Contributor Author

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{

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"
...
}

Copy link
Contributor Author

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.

@@ -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),
Copy link
Contributor

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()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@madhuravi madhuravi dismissed mfateev’s stale review February 23, 2018 21:36

Addressed comments.

@madhuravi madhuravi merged commit 0182700 into master Feb 23, 2018
@madhuravi madhuravi deleted the dynamic branch February 23, 2018 21:36
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.

5 participants