How is the ast cached in memory for concurrent scenario?

35 views
Skip to first unread message

Michael Diao

unread,
Apr 12, 2023, 6:07:15 AM4/12/23
to CEL Go Discussion Forum
Hello,

I am coding a parsing of rule engine with CEL-GO. Saddly, it costs a lot of performance in my server than cel.Compile(expression). 

So, the solution I came up with is to cache the ast result generated by cel.Compile(expression) into memory in a separate goroutine; other business goroutines access the cache concurrently, use expression to directly check the corresponding ast from the cache, and pass it to Different env, then env can directly call the Program method and Eval method to complete the expression calculation. This avoids repeatedly compiling expressions, which improves performance.

code example:
// in cache produce goroutine
func productAst() (astCache map[string]*expr.CheckedExpr) {
         astCache = make(map[string]*expr.CheckedExpr)
         env, _ := NewEnv(nil)
          for _, v := range rules {
              ast, iss := env.Compile(v)
              fmt.Printf("rule=%v, iss=%v\n", v, iss)
              checkedExpr, err := cel.AstToCheckedExpr(ast)
              fmt.Printf("rule=%v, err=%v\n", v, err)
              astCache[v] = checkedExpr
          }

return astCache
}
 
// in business goroutine, read astCache
for i, req := range requests {
wg.Add(1)
go func(i int, req *Req) {
defer wg.Done()
ctx := map[string]interface{}{
"req": req,
}

env, _ := NewEnv(ctx)

for _, exp := range expressions {
                               // ignore the question for concurrently read and write map, just demo
ast := cel.CheckedExprToAst(AstCache[exp])
prg, err := env.Program(ast)
if err != nil {
fmt.Printf("exp=%v: %v\n", exp, err)
}

out, detail, err := prg.Eval(map[string]interface{}{})
fmt.Printf("go[%v], exp=%v: out=%v, detail=%v, err=%v\n\n\n", i, exp, out, detail, err)
}
}(i, req)

My questions are:
In a concurrent scenario, if multiple goroutines jointly access the same ast object, will there be concurrency issues? 

Will the variables in this ast object be written? 

Is the ast a read-only object after it is generated? 

Or what is the best way to cache the AST?

Thank you





Tristan Swadell

unread,
Apr 12, 2023, 2:23:27 PM4/12/23
to Michael Diao, CEL Go Discussion Forum
Hi Michael,

The Ast is read-only post-compile, and is safe to share among processes. You can create multiple Program instances from a single Ast, and you should also be able to evaluate a single Program concurrently with multiple inputs since the evaluation is stateless (assuming that your functions are also stateless).

If you're trying to store the AST, you would first convert it to a CheckedExpr (protobuf), store it, and then rehydrate an Ast from the retrieved CheckedExpr. If you're just working with in-memory objects, the you can cache the Ast value directly (or Program)

Cheers,

-Tristan

--
You received this message because you are subscribed to the Google Groups "CEL Go Discussion Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cel-go-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cel-go-discuss/77a55c81-8814-43fb-9903-278796a19226n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages