package mineplex.reportserver; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.time.DurationFormatUtils; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * Establishes and maintains a connection to Redis. */ public class RedisConnectionHandler implements Runnable { private final String _name; private final JedisPool _jedisPool; private final RedisCommandHandler _handler; private final String[] _channels; private final Logger _logger; private long _lastConnectionMillis = -1; private Throwable _lastThrowable = null; public RedisConnectionHandler(String name, JedisPool jedisPool, RedisCommandHandler handler, String[] channels, Logger logger) { _name = name; _jedisPool = jedisPool; _handler = handler; _channels = channels; _logger = logger; Validate.isTrue(channels.length > 0, "Must provide at least one channel."); } @Override public void run() { while (!Thread.interrupted()) { try { registerChannelHandlers(); } catch (Throwable e) { // Only log new errors (prevents same error being spammed) if (_lastThrowable == null || !e.getClass().equals(_lastThrowable.getClass())) { if (_lastThrowable == null) // connection just failed { _lastConnectionMillis = System.currentTimeMillis(); } _logger.log(Level.SEVERE, prefixMessage( "Exception in Redis connection" + (_lastConnectionMillis != -1 ? " (no connection for " + getLastConnectionDuration() + ")" : "") + ", attempting to regain connection." ), e); _lastThrowable = e; } try { Thread.sleep(1000 * 5); } catch (InterruptedException ignored) {} } } _jedisPool.destroy(); _logger.warning("Thread interrupted, end of connection."); } private void registerChannelHandlers() { try (Jedis jedis = _jedisPool.getResource()) { connectionEstablished(); jedis.subscribe(_handler, _channels); } } private void connectionEstablished() { // subscribe blocks so we need to do all this before _logger.info( _lastThrowable == null ? prefixMessage("Connected.") : prefixMessage(String.format("Connected after %s.", getLastConnectionDuration())) ); _lastThrowable = null; } private String prefixMessage(String message) { return String.format("[%s] %s", _name, message); } private String getLastConnectionDuration() { return DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - _lastConnectionMillis, true, true); } }