/// <summary> /// When error=null => error cleared. When msg==null => exceptions surfaced from DoPulse() /// </summary> internal void FailoverDestination(Sink sink, Exception error, Message msg) { if (m_NestedFailureCount >= MAX_NESTED_FAILURES) { return; //stop cascade recursion } m_NestedFailureCount++; try { if (error == null) //error lifted { if (sink == m_FailoverErrorSink) { m_FailoverErrorSink = null; m_FailoverError = null; } return; } if (msg == null) { return; //i.e. OnPulse() } var failoverName = sink.Failover; if (string.IsNullOrEmpty(failoverName)) { failoverName = this.DefaultFailover; } if (string.IsNullOrEmpty(failoverName)) { return; //nowhere to failover } Sink failover = null; lock (m_Sinks) failover = m_Sinks.FirstOrDefault(d => string.Equals(d.Name, failoverName, StringComparison.InvariantCultureIgnoreCase)); if (failover == null) { return; } if (failover == sink) { return; //circular reference, cant fail into destination that failed } try { failover.SendRegularAndFailures(msg); if (sink.GenerateFailoverMessages || failover.GenerateFailoverMessages) { var emsg = new Message(); emsg.Type = MessageType.Error; emsg.From = sink.Name; emsg.Topic = CoreConsts.LOG_TOPIC; emsg.Text = string.Format( StringConsts.LOGSVC_FAILOVER_MSG_TEXT, msg.Guid, sink.Name, failover.Name, sink.AverageProcessingTimeMs); emsg.RelatedTo = msg.Guid; emsg.Exception = error; failover.SendRegularAndFailures(emsg); } failover.DoPulse(); } catch (Exception failoverError) { m_FailoverErrorSink = failover; m_FailoverError = failoverError; } } finally { m_NestedFailureCount--; } }