-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #339 from aol/Issue-316-AddElasticacheSupport
Issue 316 add elasticache support
- Loading branch information
Showing
9 changed files
with
348 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
apply plugin: 'groovy' | ||
apply plugin: 'java' | ||
repositories {} | ||
|
||
description = 'micro-elasticache' | ||
dependencies { | ||
compile group: 'com.amazonaws', name: 'aws-java-sdk-elasticache', version: '1.11.126' | ||
compile group: 'net.spy', name: 'spymemcached', version: '2.12.3' | ||
compile project(':micro-core') | ||
compile project(':micro-guava') | ||
testCompile group: 'org.codehaus.groovy', name: 'groovy-all', version:'2.3.3' | ||
testCompile(group: 'org.spockframework', name: 'spock-core', version:'0.7-groovy-2.0') { exclude(module: 'groovy-all') } | ||
testCompile group: 'com.cyrusinnovation', name: 'mockito-groovy-support', version:'1.3' | ||
testCompile 'cglib:cglib-nodep:2.2' | ||
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version:hamcrestVersion | ||
testCompile project(':micro-grizzly-with-jersey') | ||
} | ||
|
||
sourceSets { | ||
main { | ||
java { srcDirs = ['src/main/java']} | ||
resources { srcDir 'src/main/resources' } | ||
} | ||
|
||
test { | ||
java { srcDirs = []} | ||
groovy { srcDirs = ['src/test/java'] } | ||
resources { srcDir 'src/test/resources' } | ||
} | ||
|
||
} | ||
|
||
modifyPom { | ||
project { | ||
name 'Microserver elasticache' | ||
description 'Opinionated rest microservices' | ||
url 'https://github.com/aol/micro-server' | ||
inceptionYear '2015' | ||
|
||
groupId 'com.aol.microservices' | ||
artifactId 'micro-elasticache' | ||
version "$version" | ||
|
||
|
||
scm { | ||
url 'scm:[email protected]:aol/micro-server.git' | ||
connection 'scm:[email protected]:aol/micro-server.git' | ||
developerConnection 'scm:[email protected]:aol/micro-server.git' | ||
} | ||
|
||
licenses { | ||
license { | ||
name 'The Apache Software License, Version 2.0' | ||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt' | ||
distribution 'repo' | ||
} | ||
} | ||
|
||
developers { | ||
developer { | ||
id 'johnmcclean-aol' | ||
name 'John McClean' | ||
email '[email protected]' | ||
} | ||
developer { | ||
id 'morrowgi' | ||
name 'Gordon Morrow' | ||
email '[email protected]' | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
extraArchive { | ||
sources = true | ||
tests = true | ||
javadoc = true | ||
} | ||
|
||
nexus { | ||
sign = true | ||
repositoryUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2' | ||
snapshotRepositoryUrl = 'https://oss.sonatype.org/content/repositories/snapshots' | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Elasticache plugin for BASE microservices | ||
|
||
[micro-elasticache example apps](https://github.com/aol/micro-server/tree/master/micro-elasticache/src/test/java/app) | ||
|
||
Basically Available Soft statE | ||
|
||
* Simple Memcached Client (ElastiCache as distributed / persistent map) | ||
|
||
|
||
## Configurable properties | ||
|
||
Key used to store data used by the configured ManfiestComparator in Couchbase (default is default-key) | ||
|
||
elasticache.hostname is configuration endpoint of the elasticache cluster | ||
elasticache.portis the port of the elasticache cluster | ||
elasticache.retry.after.seconds is the number of seconds between each retry | ||
elasticache.max.retries is the maximum number of retries before client throws error and gives up | ||
|
||
|
||
## Getting The Microserver Couchbase Plugin | ||
|
||
|
||
### Maven | ||
```xml | ||
<dependency> | ||
<groupId>com.aol.microservices</groupId> | ||
<artifactId>micro-elasticache</artifactId> | ||
<version>x.yz</version> | ||
</dependency> | ||
``` | ||
### Gradle | ||
```groovy | ||
compile 'com.aol.microservices:micro-elasticache:x.yz' | ||
``` |
73 changes: 73 additions & 0 deletions
73
micro-elasticache/src/main/java/com/aol/micro/server/elasticache/ConfigureElasticache.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.aol.micro.server.elasticache; | ||
|
||
|
||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import net.spy.memcached.*; | ||
|
||
import java.io.IOException; | ||
import java.net.URISyntaxException; | ||
import java.util.ArrayList; | ||
|
||
|
||
import net.spy.memcached.auth.AuthDescriptor; | ||
import net.spy.memcached.auth.PlainCallbackHandler; | ||
import net.spy.memcached.MemcachedClient; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.util.StringUtils; | ||
|
||
import java.net.InetSocketAddress; | ||
|
||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@Slf4j | ||
@Configuration | ||
public class ConfigureElasticache { | ||
|
||
|
||
private final String hostname; | ||
private final int port; | ||
private final int retryAfterSecs; | ||
private final int maxRetries; | ||
|
||
@Autowired | ||
public ConfigureElasticache( @Value("${elasticache.hostname:null}") String hostname, | ||
@Value("${elasticache.port:6379}") int port, | ||
@Value("${elasticache.retry.after.seconds:1}") int retryAfterSecs, | ||
@Value("${elasticache.max.retries:3}") int maxRetries) { | ||
this.hostname = hostname; | ||
this.port = port; | ||
this.retryAfterSecs = retryAfterSecs; | ||
this.maxRetries = maxRetries; | ||
} | ||
|
||
|
||
@Bean(name = "transientCache") | ||
public DistributedCacheManager transientCache() throws IOException, URISyntaxException { | ||
try { | ||
log.info("Creating Memcached Data connection for elasticache cluster: {}", hostname); | ||
return new TransientElasticacheDataConnection(createMemcachedClient(), retryAfterSecs, maxRetries); | ||
} | ||
catch (Exception e) { | ||
log.error("Failed to create transient data connection", e); | ||
return null; | ||
} | ||
} | ||
|
||
@Bean(name = "memcachedClient") | ||
public MemcachedClient createMemcachedClient() throws IOException { | ||
try { | ||
log.info("Starting an instance of memcache client towards elasticache cluster"); | ||
return new MemcachedClient(new InetSocketAddress(hostname, port)); | ||
} catch (IOException e) { | ||
log.error("Could not initilise connection to elasticache cluster", e); | ||
return null; | ||
} | ||
|
||
} | ||
} | ||
|
9 changes: 9 additions & 0 deletions
9
...o-elasticache/src/main/java/com/aol/micro/server/elasticache/DistributedCacheManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.aol.micro.server.elasticache; | ||
import java.util.Optional; | ||
|
||
public interface DistributedCacheManager<V> { | ||
void setConnectionTested(boolean result); | ||
boolean isAvailable(); | ||
boolean add(String key, int exp, V value); | ||
Optional<V> get(String key); | ||
} |
12 changes: 12 additions & 0 deletions
12
micro-elasticache/src/main/java/com/aol/micro/server/elasticache/ElasticachePlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.aol.micro.server.elasticache; | ||
|
||
import com.aol.cyclops.data.collections.extensions.persistent.PSetX; | ||
import com.aol.micro.server.Plugin; | ||
|
||
public class ElasticachePlugin implements Plugin { | ||
|
||
@Override | ||
public PSetX<Class> springClasses() { | ||
return PSetX.of(ConfigureElasticache.class); | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
...he/src/main/java/com/aol/micro/server/elasticache/TransientElasticacheDataConnection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package com.aol.micro.server.elasticache; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
import java.util.Optional; | ||
import net.spy.memcached.MemcachedClient; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
|
||
@Slf4j | ||
public class TransientElasticacheDataConnection<V> implements DistributedCacheManager<V> { | ||
|
||
private volatile boolean available = false; | ||
private final MemcachedClient memcachedClient; | ||
private final int retryAfterSec; | ||
private final int maxTry; | ||
|
||
public TransientElasticacheDataConnection(MemcachedClient memcachedClient,int retryAfterSec, int maxTry) { | ||
this.memcachedClient = memcachedClient; | ||
this.retryAfterSec = retryAfterSec; | ||
this.maxTry = maxTry; | ||
} | ||
|
||
@Override | ||
public boolean add(final String key, int exp, final Object value) { | ||
|
||
log.trace("Memcached add operation on key '{}', with value:{}", key, value); | ||
boolean success = false; | ||
int tryCount = 0; | ||
|
||
do { | ||
try { | ||
if (tryCount > 0) { | ||
Thread.sleep(retryAfterSec * 1000); | ||
log.warn("retrying operation #{}", tryCount); | ||
} | ||
tryCount++; | ||
success = memcachedClient.add(key, exp, value) | ||
.get(); | ||
} catch (final Exception e) { | ||
log.warn("memcache set: {}", e.getMessage()); | ||
} | ||
} while (!success && tryCount < maxTry); | ||
|
||
if (!success) { | ||
log.error("Failed to add key to Elasticache {}", key); | ||
} | ||
if (success && tryCount > 1) { | ||
log.info("Connection restored OK to Elasticache cluster"); | ||
} | ||
|
||
available = success; | ||
return success; | ||
} | ||
|
||
@Override | ||
public Optional<V> get(String key) { | ||
return (Optional<V>) Optional.ofNullable(memcachedClient.get(key)); | ||
} | ||
|
||
@Override | ||
public boolean isAvailable() { | ||
return available; | ||
} | ||
|
||
@Override | ||
public final void setConnectionTested(final boolean available) { | ||
this.available = available; | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
micro-elasticache/src/main/resources/META-INF/services/com.aol.micro.server.Plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
com.aol.micro.server.elasticache.ElasticachePlugin |
62 changes: 62 additions & 0 deletions
62
...c/test/java/com/aol/micros/server/elasticache/TransientElasticacheDataConnectionTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.aol.micros.server.elasticache; | ||
|
||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.stub; | ||
import static org.junit.Assert.assertEquals; | ||
import com.aol.micro.server.elasticache.TransientElasticacheDataConnection; | ||
import net.spy.memcached.internal.OperationFuture; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import net.spy.memcached.MemcachedClient; | ||
import java.util.Optional; | ||
|
||
public class TransientElasticacheDataConnectionTest { | ||
|
||
MemcachedClient memcachedClient; | ||
|
||
@Before | ||
public void setup() { | ||
memcachedClient = mock(MemcachedClient.class); | ||
|
||
stub(memcachedClient.get("key1")).toReturn("value1"); | ||
stub(memcachedClient.get("key2")).toReturn("value2"); | ||
OperationFuture<Boolean> mockedFuture = mock(OperationFuture.class); | ||
stub(memcachedClient.add("keyAdd", 3600, "valueadd")).toReturn(mockedFuture); | ||
} | ||
|
||
@Test | ||
public void happyPathGetTest() { | ||
TransientElasticacheDataConnection transientClient = new TransientElasticacheDataConnection(memcachedClient, 3, 1); | ||
assertEquals(Optional.ofNullable("value1"), transientClient.get("key1")); | ||
assertEquals(Optional.ofNullable("value2"), transientClient.get("key2")); | ||
} | ||
|
||
@Test | ||
public void notExistingKeyGetTest() { | ||
TransientElasticacheDataConnection transientClient = new TransientElasticacheDataConnection(memcachedClient, 3, 1); | ||
assertEquals(Optional.empty(), transientClient.get("key3")); | ||
} | ||
|
||
@Test | ||
public void notExistingKeyPutTest() { | ||
TransientElasticacheDataConnection transientClient = new TransientElasticacheDataConnection(memcachedClient, 3, 1); | ||
assertEquals(false, transientClient.add("keyAdd", 3600, "valueadd")); | ||
} | ||
|
||
@Test | ||
public void testIsAvailableFalse() { | ||
TransientElasticacheDataConnection transientClient = new TransientElasticacheDataConnection(memcachedClient, 3, 1); | ||
transientClient.setConnectionTested(false); | ||
assertEquals(false, transientClient.isAvailable()); | ||
} | ||
|
||
@Test | ||
public void testIsAvailableTrue() { | ||
TransientElasticacheDataConnection transientClient = new TransientElasticacheDataConnection(memcachedClient, 3, 1); | ||
transientClient.setConnectionTested(true); | ||
assertEquals(true, transientClient.isAvailable()); | ||
} | ||
|
||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters