Typed config: A refactor story

Back in my days with Google Cloud Support, we wrote and maintained a case automation system. It would regularly inspect all our support cases and apply rules against them that checked for certain conditions and then executed certain actions.

Our config was a text protobuf specifying each of the rules something like:

rule {
  condition {
    type: "some.module.CheckResponseSLO"
    params: [
      {
        key: "slo_seconds"
        value: "3600"
      }
    ]
  }
  action {
    type: "some.module.EmailCaseOwner"
    params: [
      {
        key: "message"
        value: "Case {case.id} has exceeded SLO"
      }
    ]
  }
}

On initialization the classes specified in the type parameter would be dynamically loaded and called with the params as kwargs. Parameter values would be parsed on the fly, often including comma separated arrays and enums.

We had numerous operational issues caused by typos in parameter keys, values that did not convert to the correct type as expected or required parameters missing. Both because of the actions side effects and permissions to access the case data, one could not run the config locally.

My solution was to move from this generic config format to one fully specified in protobuf. Each action would provide a protobuf extension defining a strongly typed configuration specification. Thus the configuration became:

rule {
  condition {
    type: "some.module.CheckResponseSLO"
    [some.module.CheckResponseSLO] {
      slo_seconds: 3600
    }
  }
  action {
    type: "some.module.EmailCaseOwner"
    [some.module.EmailCaseOwner] {
      message: "Case {case.id} has exceeded SLO"
    }
  }
}

This has the following benefits:

  • The parameter names are type checked
  • The parameter values can be any protobuf supported type, including enums, messages and repeated values.
  • No type conversions have to be done in code.
  • Validation can be done as part of the code submission process1
  1. This could have been implemented in the old syntax, but would have required keeping validation code in sync with the implementation. ↩︎

Posted

in

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *