Skip to content

Commit 04b6582

Browse files
rica-v3rica.rdo
andauthored
Issues/#5 Add fallback-mode and health-check (#6)
* Modify HibernateArcusRegionFactory.shutdown to call clientPool.shutdown() * Remove HibernateArcusRegionFactory.nextTimestamp() not to override * Add fallbackMode and fallBackEnabled configs * Delete main/resources/logback.xml log config conflicts the project that uses the hibernate-arcus * Modify HibernateArcusRegionFactory constructor param * Modify ArcusClientConfig params by removing connectionObserver and adding reconnectIntervalInSec * Add HibernateArcusClientFactory.healthCheckArcusCluster setting fallbackMode on and off * Modify ArcusClientConfig.createArcusClientPool not to set TimeoutExceptionThreshold * Extract scheduledExecutorService in HibernateArcusClientFactory.healthCheckArcusCluster into class field * Update version 1.1.0-SNAPSHOT * Add "hibernate.cache.arcus.healthCheckIntervalInSec" properties default 10 * Modify HibernateArcusClientFactory.healthCheckArcusCluster() not to execute in case of fallbackDisabled * Add HibernateArcusClientFactoryTest for fallback mode Co-authored-by: rica.rdo <rica.rdo@kakaopaycorp.com>
1 parent 39f0be8 commit 04b6582

File tree

9 files changed

+166
-107
lines changed

9 files changed

+166
-107
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66

77
group='com.github.kims-developergroup'
88
archivesBaseName='hibernate-arcus'
9-
version='1.0.0-RELEASE'
9+
version='1.1.0-SNAPSHOT'
1010

1111
repositories {
1212
mavenCentral()

src/main/java/com/devookim/hibernatearcus/client/HibernateArcusClientFactory.java

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,73 @@
33
import com.devookim.hibernatearcus.config.ArcusClientConfig;
44
import lombok.extern.slf4j.Slf4j;
55
import net.spy.memcached.ArcusClientPool;
6-
import net.spy.memcached.ConnectionObserver;
76

87
import java.net.SocketAddress;
8+
import java.util.Collection;
9+
import java.util.Map;
10+
import java.util.concurrent.Executors;
11+
import java.util.concurrent.ScheduledExecutorService;
12+
import java.util.concurrent.TimeUnit;
13+
import java.util.concurrent.atomic.AtomicBoolean;
914

1015
@Slf4j
11-
public class HibernateArcusClientFactory implements ConnectionObserver {
16+
public class HibernateArcusClientFactory {
17+
public final boolean fallbackEnabled;
1218
private final ArcusClientPool clientPool;
19+
private final AtomicBoolean fallbackMode;
20+
private final ScheduledExecutorService scheduledExecutorService;
21+
private final int healthCheckIntervalInSec;
1322

1423
public HibernateArcusClientFactory(ArcusClientConfig clientConfig) {
15-
this.clientPool = clientConfig.getArcusClientPool();
24+
this.clientPool = clientConfig.createArcusClientPool();
25+
fallbackEnabled = clientConfig.fallbackEnabled;
26+
fallbackMode = new AtomicBoolean(clientConfig.initFallbackMode);
27+
healthCheckIntervalInSec = clientConfig.healthCheckIntervalInSec;
28+
scheduledExecutorService = Executors.newScheduledThreadPool(1,
29+
runnable -> new Thread(runnable,"HibernateArcusClientFactoryHealthChecker"));
30+
healthCheckArcusCluster(scheduledExecutorService);
1631
}
1732

1833
public void shutdown() {
34+
scheduledExecutorService.shutdown();
35+
clientPool.shutdown();
1936
log.info("ArcusClient shutdown");
2037
}
2138

22-
public Long nextTimeStamp(long currentTimeStamp, String TIMESTAMP_KEY) {
23-
long timeStamp = (long) clientPool.get(TIMESTAMP_KEY);
24-
if (timeStamp < currentTimeStamp) {
25-
clientPool.set(TIMESTAMP_KEY, -1, currentTimeStamp);
26-
}
27-
return Math.max(timeStamp, currentTimeStamp);
39+
public ArcusClientPool getClientPool() {
40+
return clientPool;
2841
}
2942

30-
public ArcusClientPool getClient() {
31-
return clientPool;
43+
public void setFallbackMode(boolean onAndOff) {
44+
if(fallbackMode.compareAndSet(!onAndOff, onAndOff)) {
45+
log.info("Fallback mode changed: {}", onAndOff);
46+
}
3247
}
3348

34-
@Override
35-
public void connectionEstablished(SocketAddress sa, int reconnectCount) {
36-
log.info("Arcus client connection established. addr: {} reconnect: {}", sa, reconnectCount);
49+
public boolean isFallbackModeOn() {
50+
return fallbackMode.get();
3751
}
3852

39-
@Override
40-
public void connectionLost(SocketAddress sa) {
41-
log.info("Arcus client connection is lost. addr: {}", sa);
53+
public void healthCheckArcusCluster(ScheduledExecutorService scheduledExecutorService) {
54+
if (!fallbackEnabled) {
55+
return;
56+
}
57+
scheduledExecutorService.scheduleWithFixedDelay(() -> {
58+
log.trace("ping...");
59+
Map<SocketAddress, Map<String, String>> stats = clientPool.getStats();
60+
if(stats.size() == 0) {
61+
setFallbackMode(true);
62+
return;
63+
}
4264

65+
Collection<Map<String, String>> nodes = stats.values();
66+
for (Map<String, String> node: nodes) {
67+
if (node.containsKey("zk_connected")
68+
&& Boolean.parseBoolean(node.get("zk_connected"))) {
69+
setFallbackMode(false);
70+
return;
71+
}
72+
}
73+
}, healthCheckIntervalInSec, healthCheckIntervalInSec, TimeUnit.SECONDS);
4374
}
4475
}

src/main/java/com/devookim/hibernatearcus/config/ArcusClientConfig.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,39 @@
11
package com.devookim.hibernatearcus.config;
22

3-
import net.spy.memcached.ArcusClient;
4-
import net.spy.memcached.ArcusClientPool;
5-
import net.spy.memcached.ConnectionFactoryBuilder;
3+
import lombok.extern.slf4j.Slf4j;
4+
import net.spy.memcached.*;
65

6+
import java.util.Map;
7+
8+
@Slf4j
79
public class ArcusClientConfig {
10+
public final boolean fallbackEnabled;
11+
public final boolean initFallbackMode;
12+
public final int healthCheckIntervalInSec;
813
private final int poolSize;
14+
private final Map<String, String> properties;
915
private final String host;
1016
private final String serviceCode;
1117

12-
public ArcusClientConfig(String host,
13-
String serviceCode,
14-
int poolSize) {
15-
this.host = host;
16-
this.serviceCode = serviceCode;
17-
this.poolSize = poolSize;
18-
}
19-
20-
public ArcusClientPool getArcusClientPool() {
21-
return createArcusClientPool();
18+
public ArcusClientConfig(Map<String, String> properties) {
19+
this.host = properties.getOrDefault("hibernate.cache.arcus.host", "localhost:2181");
20+
this.serviceCode = properties.getOrDefault("hibernate.cache.arcus.serviceCode", "");
21+
this.poolSize = Integer.parseInt(properties.getOrDefault("hibernate.cache.arcus.poolSize", "1"));
22+
this.fallbackEnabled = Boolean.parseBoolean(properties.getOrDefault("hibernate.cache.arcus.fallbackEnabled", "true"));
23+
this.initFallbackMode = Boolean.parseBoolean(properties.getOrDefault("hibernate.cache.arcus.initFallbackMode", "false"));
24+
this.healthCheckIntervalInSec = Integer.parseInt(properties.getOrDefault("hibernate.cache.arcus.healthCheckIntervalInSec", "10"));
25+
this.properties = properties;
2226
}
2327

24-
private ArcusClientPool createArcusClientPool() {
28+
public ArcusClientPool createArcusClientPool() {
29+
log.info("Creating arcus client pool");
30+
ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();
31+
cfb.setMaxReconnectDelay(Long.parseLong(properties.getOrDefault("hibernate.cache.arcus.reconnectIntervalInSec", "10000")));
32+
cfb.setOpTimeout(Long.parseLong(properties.getOrDefault("hibernate.cache.arcus.opTimeout", "10000")));
2533
return ArcusClient.createArcusClientPool(
2634
host,
2735
serviceCode,
28-
new ConnectionFactoryBuilder(),
36+
cfb,
2937
poolSize
3038
);
3139
}

src/main/java/com/devookim/hibernatearcus/factory/HibernateArcusRegionFactory.java

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ public class HibernateArcusRegionFactory extends RegionFactoryTemplate {
3030

3131
private HibernateArcusClientFactory hibernateArcusClientFactory;
3232
private CacheKeysFactory cacheKeysFactory;
33-
protected boolean fallback;
3433

3534
@PostConstruct
3635
public void postConstruct() {
37-
log.debug("HibernateArcusRegionFactory is initialized");
36+
log.info("HibernateArcusRegionFactory is initialized");
3837
}
3938

4039
@Override
@@ -45,13 +44,8 @@ protected CacheKeysFactory getImplicitCacheKeysFactory() {
4544
@Override
4645
protected void prepareForUse(SessionFactoryOptions settings, Map properties) throws CacheException {
4746

48-
ArcusClientConfig arcusClientConfig = new ArcusClientConfig(
49-
properties.getOrDefault("hibernate.cache.arcus.host", "localhost:2181").toString(),
50-
properties.getOrDefault("hibernate.cache.arcus.serviceCode", "").toString(),
51-
Integer.parseInt(properties.getOrDefault("hibernate.cache.arcus.poolSize", 1).toString())
52-
);
47+
ArcusClientConfig arcusClientConfig = new ArcusClientConfig(properties);
5348
this.hibernateArcusClientFactory = new HibernateArcusClientFactory(arcusClientConfig);
54-
fallback = true;
5549
StrategySelector selector = settings.getServiceRegistry().getService(StrategySelector.class);
5650
cacheKeysFactory = selector.resolveDefaultableStrategy(CacheKeysFactory.class,
5751
properties.get(Environment.CACHE_KEYS_FACTORY), new HibernateArcusCacheKeysFactory());
@@ -72,19 +66,6 @@ public AccessType getDefaultAccessType() {
7266
return AccessType.TRANSACTIONAL;
7367
}
7468

75-
@Override
76-
public long nextTimestamp() {
77-
long currentTimeStamp = System.currentTimeMillis() << 12;
78-
try {
79-
return hibernateArcusClientFactory.nextTimeStamp(currentTimeStamp, "TIME_STAMP");
80-
} catch (Exception e) {
81-
if (fallback) {
82-
return super.nextTimestamp();
83-
}
84-
throw e;
85-
}
86-
}
87-
8869
@Override
8970
public DomainDataRegion buildDomainDataRegion(
9071
DomainDataRegionConfig regionConfig,
@@ -101,8 +82,7 @@ public DomainDataRegion buildDomainDataRegion(
10182

10283
@Override
10384
protected DomainDataStorageAccess createDomainDataStorageAccess(DomainDataRegionConfig regionConfig, DomainDataRegionBuildingContext buildingContext) {
104-
ArcusClientPool cacheClientPool = getCache(qualify(regionConfig.getRegionName()));
105-
return new DomainDataHibernateArcusStorageAccess(cacheClientPool, qualify(regionConfig.getRegionName()));
85+
return new DomainDataHibernateArcusStorageAccess(getClientFactory(qualify(regionConfig.getRegionName())), qualify(regionConfig.getRegionName()));
10686
}
10787

10888
@Override
@@ -112,18 +92,16 @@ public String qualify(String regionName) {
11292

11393
@Override
11494
protected StorageAccess createQueryResultsRegionStorageAccess(String regionName, SessionFactoryImplementor sessionFactory) {
115-
ArcusClientPool cacheClientPool = getCache(qualify(regionName));
116-
return new QueryCacheHibernateArcusStorageAccess(cacheClientPool, qualify(regionName));
95+
return new QueryCacheHibernateArcusStorageAccess(getClientFactory(qualify(regionName)), qualify(regionName));
11796
}
11897

11998
@Override
12099
protected StorageAccess createTimestampsRegionStorageAccess(String regionName, SessionFactoryImplementor sessionFactory) {
121-
ArcusClientPool cacheClientPool = getCache(qualify(regionName));
122-
return new HibernateArcusStorageAccess(cacheClientPool, qualify(regionName));
100+
return new HibernateArcusStorageAccess(getClientFactory(qualify(regionName)), qualify(regionName));
123101
}
124102

125-
protected ArcusClientPool getCache(String regionName) {
103+
protected HibernateArcusClientFactory getClientFactory(String regionName) {
126104
log.debug("getCache region: {}", regionName);
127-
return hibernateArcusClientFactory.getClient();
105+
return hibernateArcusClientFactory;
128106
}
129107
}

src/main/java/com/devookim/hibernatearcus/storage/DomainDataHibernateArcusStorageAccess.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.devookim.hibernatearcus.storage;
22

3+
import com.devookim.hibernatearcus.client.HibernateArcusClientFactory;
34
import lombok.extern.slf4j.Slf4j;
4-
import net.spy.memcached.ArcusClientPool;
55
import org.hibernate.cache.spi.support.AbstractReadWriteAccess;
66
import org.hibernate.engine.spi.SharedSessionContractImplementor;
77

88
@Slf4j
99
public class DomainDataHibernateArcusStorageAccess extends HibernateArcusStorageAccess {
10-
public DomainDataHibernateArcusStorageAccess(ArcusClientPool arcusClientPool, String regionName) {
11-
super(arcusClientPool, regionName);
10+
public DomainDataHibernateArcusStorageAccess(HibernateArcusClientFactory arcusClientFactory, String regionName) {
11+
super(arcusClientFactory, regionName);
1212
}
1313

1414
@Override

0 commit comments

Comments
 (0)