public void MetricsChanged(ClusterMetricsChanged @event) { var oldValue = _weightedRouteesRef.Value; var routees = oldValue.Item1; var weightedRoutees = new WeightedRoutees(routees, _cluster.SelfAddress, _metricsSelector.Weights(@event.NodeMetrics).ToImmutableDictionary(pair => pair.Key, pair => pair.Value)); // retry when CAS failure if (!_weightedRouteesRef.CompareAndSet(oldValue, Tuple.Create(routees, @event.NodeMetrics, weightedRoutees.AsOption()))) { MetricsChanged(@event); } }
/// <inheritdoc /> public override Routee Select(object message, Routee[] routees) { if (routees.Length == 0) { return(Routee.NoRoutee); } Option <WeightedRoutees> UpdateWeightedRoutees() { var oldValue = _weightedRouteesRef.Value; var(oldRoutees, oldMetrics, oldWeightedRoutees) = oldValue; if (oldRoutees.Equals(routees.ToImmutableArray())) { return(oldWeightedRoutees); } var weightedRoutees = new WeightedRoutees(routees.ToImmutableArray(), _cluster.SelfAddress, _metricsSelector.Weights(oldMetrics).ToImmutableDictionary(pair => pair.Key, pair => pair.Value)); // ignore, don't update, in case of CAS failure _weightedRouteesRef.CompareAndSet(oldValue, Tuple.Create(routees.ToImmutableArray(), oldMetrics, weightedRoutees.AsOption())); return(weightedRoutees); } var updated = UpdateWeightedRoutees(); if (updated.HasValue) { var weighted = updated.Value; if (weighted.IsEmpty) { return(Routee.NoRoutee); } return(weighted[ThreadLocalRandom.Current.Next(weighted.Total) + 1]); } else { return(routees[ThreadLocalRandom.Current.Next(routees.Length)]); } }