Время OPA PrepareForEval увеличивается экспоненциально

Мне нужно, чтобы мое приложение могло загружать политики (rego), а затем оценивать входной JSON на основе определенных политик.

Я по ошибке использовал PrepareForEvalв моем оценочном API вместо API политики загрузки. Результат меня удивил, поскольку время отклика продолжало экспоненциально увеличиваться после каждой оценки, в то время как правила оставались неизменными. Хотя после этого я понял и изменил свою логику на вызовPrepareForEvalво время загрузки политики, а затем сохраните подготовленный экземпляр запроса в моем экземпляре структуры. Но меня все еще беспокоит, если метод подготовки выполняется несколько раз при загрузке политик, тогда это все равно станет дорогостоящей операцией.

Итак, было бы здорово указать на правильный способ использования метода подготовки.

Образец кода:

// My provider
func init() {
  cachedRego := rego.New(rego.Query("data.report"))
}

// My load policy method
func loadPolicy(ctx context.Context, filename, regoPolicy string) {
  mod, err := ast.ParseModule(filename, regoPolicy)
  rego.ParsedModule(mod)(cachedRego)
}

// My evaluate method
func eval(ctx context.Context, input interface{}) {
  // after loading my policies, the following call took 1s, 2s, 5s, 10s,... respectively on eval calls
  preparedQuery, _ := cachedRego.PrepareForEval(ctx) // <- I've moved this to my load policy method and cached preparedQuery

  // this doesn’t take much time
  rs, _ := preparedQuery.Eval(ctx, rego.EvalInput(input))
}

// My use case
func main() {
  // load policies and evaluate inputs
  for _, p := range policySet1 {
    loadPolicy(context.Background(), p.filename, p.regoPolicy)
  }

  for _, inp := range inputSet1 {
    eval(context.Background(), inp)
  }


  // load more policies to the earlier set and evaluate another input set
  for _, p := range policySet2 {
    loadPolicy(context.Background(), p.filename, p.regoPolicy)
  }

  for _, inp := range inputSet2 {
    eval(context.Background(), inp)
  }
}

1 ответ

Решение

TL; DR; это, вероятно, не подходящее место для этого вопроса. Сообщите о проблеме на GitHub, если вы заметили неправильное поведение.

Чтобы ответить на ваш вопрос о том, как правильно подготовить запросы, ваша основная функция должна (как минимум) выглядеть так:

func main() {
  pq1 := loadPolicies(policySet1)
  
  for _, inp := range inputSet1 {
    eval(pq1, inp)
  }

  pq2 := loadPolicies(policySet2)
 
  for _, inp := range inputSet2 {
    eval(pq2, inp)
  }
}

Самый простой способ реализовать loadPolicies для приведенного выше примера будет примерно так:

func loadPolicies(policySet) {

  opts := []func(*rego.Rego){}

  // setup prepared query. load all modules.
  for _, p := range policySet {
    opts = append(opts, rego.Module(p.filename, p.regoPolicy))
  }

  // create new prepared query
  return rego.New(rego.Query("data.report"), opts...).PrepareForEval()
}

Тогда ваша функция eval станет:

func eval(pq, inp) {
   rs, err := pq.Eval(rego.EvalInput(inp))
   // handle err
   // interpret rs
}
Другие вопросы по тегам