github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/actor/strategy_all_for_one.go (about)

     1  package actor
     2  
     3  import "time"
     4  
     5  // NewAllForOneStrategy returns a new SupervisorStrategy which applies the given fault Directive from the decider to the
     6  // failing child and all its children.
     7  //
     8  // This strategy is appropriate when the children have a strong dependency, such that and any single one failing would
     9  // place them all into a potentially invalid state.
    10  func NewAllForOneStrategy(maxNrOfRetries int, withinDuration time.Duration, decider DeciderFunc) SupervisorStrategy {
    11  	return &allForOneStrategy{
    12  		maxNrOfRetries: maxNrOfRetries,
    13  		withinDuration: withinDuration,
    14  		decider:        decider,
    15  	}
    16  }
    17  
    18  type allForOneStrategy struct {
    19  	maxNrOfRetries int
    20  	withinDuration time.Duration
    21  	decider        DeciderFunc
    22  }
    23  
    24  var _ SupervisorStrategy = &allForOneStrategy{}
    25  
    26  func (strategy *allForOneStrategy) HandleFailure(actorSystem *ActorSystem, supervisor Supervisor, child *PID, rs *RestartStatistics, reason interface{}, message interface{}) {
    27  	directive := strategy.decider(reason)
    28  	switch directive {
    29  	case ResumeDirective:
    30  		// resume the failing child
    31  		logFailure(actorSystem, child, reason, directive)
    32  		supervisor.ResumeChildren(child)
    33  	case RestartDirective:
    34  		children := supervisor.Children()
    35  		// try restart the all the children
    36  		if strategy.shouldStop(rs) {
    37  			logFailure(actorSystem, child, reason, StopDirective)
    38  			supervisor.StopChildren(children...)
    39  		} else {
    40  			logFailure(actorSystem, child, reason, RestartDirective)
    41  			supervisor.RestartChildren(children...)
    42  		}
    43  	case StopDirective:
    44  		children := supervisor.Children()
    45  		// stop all the children, no need to involve the crs
    46  		logFailure(actorSystem, child, reason, directive)
    47  		supervisor.StopChildren(children...)
    48  	case EscalateDirective:
    49  		// send failure to parent
    50  		// supervisor mailbox
    51  		// do not log here, log in the parent handling the error
    52  		supervisor.EscalateFailure(reason, message)
    53  	}
    54  }
    55  
    56  func (strategy *allForOneStrategy) shouldStop(rs *RestartStatistics) bool {
    57  	// supervisor says this child may not restart
    58  	if strategy.maxNrOfRetries == 0 {
    59  		return true
    60  	}
    61  
    62  	rs.Fail()
    63  
    64  	if rs.NumberOfFailures(strategy.withinDuration) > strategy.maxNrOfRetries {
    65  		rs.Reset()
    66  		return true
    67  	}
    68  
    69  	return false
    70  }