internal void KeepAlive() { if (!(physical?.IsIdle() ?? false)) { return; // don't pile on if already doing something } var commandMap = Multiplexer.CommandMap; Message msg = null; var features = ServerEndPoint.GetFeatures(); switch (ConnectionType) { case ConnectionType.Interactive: msg = ServerEndPoint.GetTracerMessage(false); msg.SetSource(ResultProcessor.Tracer, null); break; case ConnectionType.Subscription: if (commandMap.IsAvailable(RedisCommand.PING) && features.PingOnSubscriber) { msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.PING); msg.SetSource(ResultProcessor.Tracer, null); } else if (commandMap.IsAvailable(RedisCommand.UNSUBSCRIBE)) { msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.UNSUBSCRIBE, (RedisChannel)Multiplexer.UniqueId); msg.SetSource(ResultProcessor.TrackSubscriptions, null); } break; } if (msg != null) { msg.SetInternalCall(); Multiplexer.Trace("Enqueue: " + msg); Multiplexer.OnInfoMessage($"heartbeat ({physical?.LastWriteSecondsAgo}s >= {ServerEndPoint?.WriteEverySeconds}s, {physical?.GetSentAwaitingResponseCount()} waiting) '{msg.CommandAndKey}' on '{PhysicalName}' (v{features.Version})"); physical?.UpdateLastWriteTime(); // pre-emptively #pragma warning disable CS0618 var result = TryWriteSync(msg, ServerEndPoint.IsSlave); #pragma warning restore CS0618 if (result != WriteResult.Success) { var ex = Multiplexer.GetException(result, msg, ServerEndPoint); OnInternalError(ex); } } }