SSE: Localize/Contain Errors within an Expression (#73163)

Changes SSE to not always fail all queries when one fails. Now only the query itself, and nodes that depend on it will error.
---------

Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
This commit is contained in:
Kyle Brandt
2023-09-13 13:58:16 -04:00
committed by GitHub
co-authored by Gilles De Mey
parent 01755608db
commit 35e488b22b
25 changed files with 663 additions and 679 deletions
+35 -9
View File
@@ -44,8 +44,13 @@ type Node interface {
ID() int64 // ID() allows the gonum graph node interface to be fulfilled
NodeType() NodeType
RefID() string
Execute(ctx context.Context, now time.Time, vars mathexp.Vars, s *Service) (mathexp.Results, error)
String() string
NeedsVars() []string
}
type ExecutableNode interface {
Node
Execute(ctx context.Context, now time.Time, vars mathexp.Vars, s *Service) (mathexp.Results, error)
}
// DataPipeline is an ordered set of nodes returned from DPGraph processing.
@@ -67,27 +72,48 @@ func (dp *DataPipeline) execute(c context.Context, now time.Time, s *Service) (m
dsNodes = append(dsNodes, node.(*DSNode))
}
if err := executeDSNodesGrouped(c, now, vars, s, dsNodes); err != nil {
return nil, err
}
executeDSNodesGrouped(c, now, vars, s, dsNodes)
}
for _, node := range *dp {
if groupByDSFlag && node.NodeType() == TypeDatasourceNode {
continue // already executed via executeDSNodesGrouped
}
// Don't execute nodes that have dependent nodes that have failed
var hasDepError bool
for _, neededVar := range node.NeedsVars() {
if res, ok := vars[neededVar]; ok {
if res.Error != nil {
errResult := mathexp.Results{
Error: makeDependencyError(node.RefID(), neededVar),
}
vars[node.RefID()] = errResult
hasDepError = true
break
}
}
}
if hasDepError {
continue
}
c, span := s.tracer.Start(c, "SSE.ExecuteNode")
span.SetAttributes("node.refId", node.RefID(), attribute.Key("node.refId").String(node.RefID()))
if node.NodeType() == TypeCMDNode {
cmdNode := node.(*CMDNode)
inputRefIDs := cmdNode.Command.NeedsVars()
if len(node.NeedsVars()) > 0 {
inputRefIDs := node.NeedsVars()
span.SetAttributes("node.inputRefIDs", inputRefIDs, attribute.Key("node.inputRefIDs").StringSlice(inputRefIDs))
}
defer span.End()
res, err := node.Execute(c, now, vars, s)
execNode, ok := node.(ExecutableNode)
if !ok {
return vars, makeUnexpectedNodeTypeError(node.RefID(), node.NodeType().String())
}
res, err := execNode.Execute(c, now, vars, s)
if err != nil {
return nil, err
res.Error = err
}
vars[node.RefID()] = res