4
4
5
5
package edu .caltech .ipac .firefly .core ;
6
6
7
+ import edu .caltech .ipac .firefly .data .ServerEvent ;
8
+ import edu .caltech .ipac .firefly .server .events .FluxAction ;
9
+ import edu .caltech .ipac .firefly .server .events .ServerEventManager ;
7
10
import edu .caltech .ipac .firefly .server .util .Logger ;
8
11
import edu .caltech .ipac .util .AppProperties ;
9
12
import redis .clients .jedis .Jedis ;
14
17
15
18
import java .io .File ;
16
19
import java .io .IOException ;
17
- import java .net .ConnectException ;
18
20
import java .security .MessageDigest ;
19
21
import java .security .NoSuchAlgorithmException ;
20
22
import java .time .Duration ;
23
+ import java .time .Instant ;
24
+ import java .time .ZoneId ;
25
+ import java .time .format .DateTimeFormatter ;
21
26
import java .time .temporal .ChronoUnit ;
22
27
import java .util .Arrays ;
23
28
import java .util .LinkedHashMap ;
24
29
import java .util .Map ;
25
30
26
- import static edu .caltech .ipac .firefly .core .RedisService .Status .ONLINE ;
27
- import static edu .caltech .ipac .firefly .core .RedisService .Status .OFFLINE ;
28
31
import static edu .caltech .ipac .firefly .core .Util .Try ;
29
32
30
33
45
48
* @version $Id: $
46
49
*/
47
50
public class RedisService {
48
- public enum Status {ONLINE , FAIL_TO_CONNECT , OFFLINE };
49
51
public static final String REDIS_HOST = "redis.host" ;
50
52
public static final String MAX_POOL_SIZE = "redis.max.poolsize" ;
51
53
private static final int REDIS_PORT = AppProperties .getIntProperty ("redis.port" , 6379 );
@@ -58,18 +60,14 @@ public enum Status {ONLINE, FAIL_TO_CONNECT, OFFLINE};
58
60
private static final String redisHost = AppProperties .getProperty (REDIS_HOST , "localhost" );
59
61
public static final int maxPoolSize = AppProperties .getIntProperty (MAX_POOL_SIZE , 100 );
60
62
private static JedisPool jedisPool ;
61
- private static Status status = Status . OFFLINE ;
63
+ private static Instant failSince ;
62
64
63
65
private static String getRedisPassword () {
64
66
String passwd = System .getenv ("REDIS_PASSWORD" );
65
67
if (passwd == null ) passwd = AppProperties .getProperty ("REDIS_PASSWORD" );
66
68
return passwd ;
67
69
}
68
70
69
- static {
70
- connect ();
71
- }
72
-
73
71
static JedisPool createJedisPool () {
74
72
try {
75
73
JedisPoolConfig pconfig = new JedisPoolConfig ();
@@ -103,42 +101,61 @@ static void startLocal() {
103
101
} catch (IOException ignored ) {}
104
102
}
105
103
106
- public static boolean connect () throws RuntimeException {
107
- if (jedisPool != null && !jedisPool .isClosed ()) {
108
- return true ; // already connected
109
- }
110
- jedisPool = createJedisPool ();
111
- if (jedisPool == null && redisHost .equals ("localhost" )) {
112
- // can't connect; will start up embedded version if localhost
113
- startLocal ();
114
- jedisPool = createJedisPool ();
115
- }
116
- if (jedisPool == null ) {
117
- LOG .error ("Unable to connect to Redis at " + redisHost + ":" + REDIS_PORT );
118
- status = Status .FAIL_TO_CONNECT ;
119
- return false ;
120
- } else {
121
- status = ONLINE ;
122
- return true ;
104
+ public static Instant getFailSince () { return failSince ; }
105
+
106
+ public static Jedis getConnection () throws Exception {
107
+ try {
108
+ if (jedisPool == null || jedisPool .isClosed ()) {
109
+ jedisPool = createJedisPool ();
110
+ if (jedisPool == null && redisHost .equals ("localhost" )) {
111
+ // can't connect; will start up embedded version if localhost
112
+ startLocal ();
113
+ jedisPool = createJedisPool ();
114
+ }
115
+ if (jedisPool == null || jedisPool .isClosed ()) {
116
+ if (jedisPool != null ) {
117
+ Try .it (jedisPool ::close );
118
+ jedisPool = null ;
119
+ }
120
+ throw new RuntimeException ("Unable to connect to Redis at " + redisHost + ":" + REDIS_PORT );
121
+ }
122
+ }
123
+ Jedis jedis = jedisPool .getResource ();
124
+ if (failSince != null ) updateConnectionStatus (false );
125
+ return jedis ;
126
+ } catch (Exception e ) {
127
+ if (failSince == null ) {
128
+ updateConnectionStatus (true );
129
+ }
130
+ throw e ;
123
131
}
124
132
}
125
133
134
+ // because Redis may be down, we need to use processEvent to directly send it to clients currently connected
135
+ // to this server and not rely on distributed event messaging.
136
+ public static void updateConnectionStatus (boolean lost ) {
137
+ failSince = lost ? Instant .now () : null ;
138
+ String reason = lost ? "A critical system component is currently unavailable" : "" ;
139
+
140
+ FluxAction action = new FluxAction ("app_data.appUpdate" );
141
+ action .setValue (lost , "connectionStatus" , "lost" );
142
+ action .setValue (reason , "connectionStatus" , "reason" );
143
+ ServerEventManager .processEvent (ServerEventManager .convertTo (action , ServerEvent .Scope .WORLD ));
144
+ }
145
+
126
146
public static void teardown () {
127
147
disconnect ();
128
148
File [] files = new File (DB_DIR ).listFiles ();
129
149
if (files != null ) Arrays .stream (files ).forEach (File ::delete );
130
150
}
131
151
132
152
public static void disconnect () {
133
- status = OFFLINE ;
134
153
if (jedisPool != null ) {
135
154
jedisPool .close ();
136
155
jedisPool = null ;
137
156
}
138
157
}
139
158
140
- public static Status getStatus () { return status ; }
141
-
142
159
public static Map <String , Object > getStats () {
143
160
144
161
LinkedHashMap <String , Object > stats = new LinkedHashMap <>();
@@ -187,13 +204,8 @@ public static void addStat(Map<String, Object> stats, Jedis redis, String key) {
187
204
}
188
205
189
206
public static String getRedisHostPortDesc () {
190
- return redisHost + ":" + REDIS_PORT + " (" + getStatus () + ")" ;
191
- }
192
-
193
- public static Jedis getConnection () throws Exception {
194
- if (connect ()) {
195
- return jedisPool .getResource ();
196
- }
197
- throw new ConnectException ("Unable to connect to Redis at " + redisHost + ":" + REDIS_PORT );
207
+ String status = failSince == null ? "OK" :
208
+ "Failed since " + DateTimeFormatter .ofPattern ("yyyy-MM-dd HH:mm:ss" ).withZone (ZoneId .systemDefault ()).format (failSince );
209
+ return redisHost + ":" + REDIS_PORT + " (%s)" .formatted (status );
198
210
}
199
211
}
0 commit comments