github.com/onflow/flow-go@v0.33.17/engine/access/rpc/backend/node_selector.go (about)

     1  package backend
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/onflow/flow-go/model/flow"
     7  )
     8  
     9  // maxNodesCnt is the maximum number of nodes that will be contacted to complete an API request.
    10  const maxNodesCnt = 3
    11  
    12  // NodeSelector is an interface that represents the ability to select node identities that the access node is trying to reach.
    13  // It encapsulates the internal logic of node selection and provides a way to change implementations for different types
    14  // of nodes. Implementations of this interface should define the Next method, which returns the next node identity to be
    15  // selected. HasNext checks if there is next node available.
    16  type NodeSelector interface {
    17  	Next() *flow.Identity
    18  	HasNext() bool
    19  }
    20  
    21  // NodeSelectorFactory is a factory for creating node selectors based on factory configuration and node type.
    22  // Supported configurations:
    23  // circuitBreakerEnabled = true - nodes will be pseudo-randomly sampled and picked in-order.
    24  // circuitBreakerEnabled = false - nodes will be picked from proposed list in-order without any changes.
    25  type NodeSelectorFactory struct {
    26  	circuitBreakerEnabled bool
    27  }
    28  
    29  // SelectNodes selects the configured number of node identities from the provided list of nodes
    30  // and returns the node selector to iterate through them.
    31  func (n *NodeSelectorFactory) SelectNodes(nodes flow.IdentityList) (NodeSelector, error) {
    32  	var err error
    33  	// If the circuit breaker is disabled, the legacy logic should be used, which selects only a specified number of nodes.
    34  	if !n.circuitBreakerEnabled {
    35  		nodes, err = nodes.Sample(maxNodesCnt)
    36  		if err != nil {
    37  			return nil, fmt.Errorf("sampling failed: %w", err)
    38  		}
    39  	}
    40  
    41  	return NewMainNodeSelector(nodes), nil
    42  }
    43  
    44  // MainNodeSelector is a specific implementation of the node selector.
    45  // Which performs in-order node selection using fixed list of pre-defined nodes.
    46  type MainNodeSelector struct {
    47  	nodes flow.IdentityList
    48  	index int
    49  }
    50  
    51  var _ NodeSelector = (*MainNodeSelector)(nil)
    52  
    53  func NewMainNodeSelector(nodes flow.IdentityList) *MainNodeSelector {
    54  	return &MainNodeSelector{nodes: nodes, index: 0}
    55  }
    56  
    57  // HasNext returns true if next node is available.
    58  func (e *MainNodeSelector) HasNext() bool {
    59  	return e.index < len(e.nodes)
    60  }
    61  
    62  // Next returns the next node in the selector.
    63  func (e *MainNodeSelector) Next() *flow.Identity {
    64  	if e.index < len(e.nodes) {
    65  		next := e.nodes[e.index]
    66  		e.index++
    67  		return next
    68  	}
    69  	return nil
    70  }