Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

Commit c503408

Browse files
committed
Hystrix based resilient connector
1 parent c85211c commit c503408

File tree

10 files changed

+1041
-0
lines changed

10 files changed

+1041
-0
lines changed

Diff for: connectors/pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<module>grizzly-connector</module>
6262
<module>jetty-connector</module>
6363
<module>netty-connector</module>
64+
<module>resilient-connector</module>
6465
</modules>
6566

6667
<dependencies>

Diff for: connectors/resilient-connector/.gitignore

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# maven noise
2+
target/
3+
4+
# gradle noise
5+
.gradle
6+
7+
# osx noise
8+
.DS_Store
9+
profile
10+
11+
# IntelliJ Idea noise
12+
.idea
13+
*.iws
14+
*.ipr
15+
*.iml
16+
*.releaseBackup
17+
atlassian-ide-plugin.xml
18+
19+
# NB noise
20+
nbactions.xml
21+
nb-configuration.xml
22+
23+
# Eclipse noise
24+
.settings
25+
.settings/*
26+
.project
27+
.classpath
28+
29+
# Maven plugins noise
30+
dependency-reduced-pom.xml
31+
pom.xml.versionsBackup

Diff for: connectors/resilient-connector/pom.xml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
<parent>
4+
<groupId>org.glassfish.jersey.connectors</groupId>
5+
<artifactId>project</artifactId>
6+
<version>2.24-SNAPSHOT</version>
7+
</parent>
8+
<artifactId>jersey-resilient-connector</artifactId>
9+
10+
<description>Jersey Resilient Client Transport via Hystrix</description>
11+
12+
<properties>
13+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
14+
<hystrix.core.version>1.5.5</hystrix.core.version>
15+
</properties>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>com.netflix.hystrix</groupId>
20+
<artifactId>hystrix-core</artifactId>
21+
<version>${hystrix.core.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
25+
<artifactId>jersey-test-framework-provider-bundle</artifactId>
26+
<version>${project.version}</version>
27+
<type>pom</type>
28+
<scope>test</scope>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.glassfish.jersey.connectors</groupId>
32+
<artifactId>jersey-grizzly-connector</artifactId>
33+
<version>${project.version}</version>
34+
<scope>test</scope>
35+
</dependency>
36+
</dependencies>
37+
38+
<build>
39+
<plugins>
40+
<plugin>
41+
<groupId>com.sun.istack</groupId>
42+
<artifactId>maven-istack-commons-plugin</artifactId>
43+
<inherited>true</inherited>
44+
</plugin>
45+
<plugin>
46+
<groupId>org.codehaus.mojo</groupId>
47+
<artifactId>build-helper-maven-plugin</artifactId>
48+
<inherited>true</inherited>
49+
</plugin>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-compiler-plugin</artifactId>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.glassfish.jersey.resilient.connector;
2+
3+
import org.glassfish.jersey.client.ClientRequest;
4+
5+
import com.netflix.hystrix.HystrixCommandGroupKey;
6+
import com.netflix.hystrix.HystrixCommandKey;
7+
import com.netflix.hystrix.HystrixCommandProperties;
8+
import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
9+
import com.netflix.hystrix.HystrixCommandProperties.Setter;
10+
11+
public class DefaultHystrixCommandConfigProvider implements ResilientConnectorProvider.HystrixCommandConfigProvider {
12+
13+
@Override
14+
public String commandName(ClientRequest requestContext) {
15+
return requestContext.getUri().getPath();
16+
}
17+
18+
@Override
19+
public com.netflix.hystrix.HystrixCommand.Setter commandConfig(ClientRequest requestContext) {
20+
return com.netflix.hystrix.HystrixCommand.Setter
21+
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("JerseyClientHystrixCommand"))
22+
.andCommandKey(HystrixCommandKey.Factory.asKey(commandName(requestContext)))
23+
.andCommandPropertiesDefaults(defaultCommandProperties());
24+
}
25+
26+
@Override
27+
public com.netflix.hystrix.HystrixObservableCommand.Setter observableCommandConfig(ClientRequest requestContext) {
28+
return com.netflix.hystrix.HystrixObservableCommand.Setter
29+
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("JerseyClientHystrixObservableCommand"))
30+
.andCommandKey(HystrixCommandKey.Factory.asKey(commandName(requestContext)))
31+
.andCommandPropertiesDefaults(defaultCommandProperties());
32+
}
33+
34+
private static Setter defaultCommandProperties() {
35+
return HystrixCommandProperties.Setter()
36+
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
37+
.withExecutionTimeoutEnabled(false);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package org.glassfish.jersey.resilient.connector;
2+
3+
import java.util.concurrent.Future;
4+
5+
import javax.ws.rs.client.Client;
6+
import javax.ws.rs.core.Configuration;
7+
8+
import org.glassfish.jersey.client.ClientRequest;
9+
import org.glassfish.jersey.client.ClientResponse;
10+
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
11+
import org.glassfish.jersey.client.spi.Connector;
12+
import org.glassfish.jersey.internal.util.PropertiesHelper;
13+
import org.glassfish.jersey.resilient.connector.ResilientConnectorProvider.HystrixCommandConfigProvider;
14+
15+
import com.netflix.hystrix.HystrixCommand;
16+
import com.netflix.hystrix.HystrixObservableCommand;
17+
18+
import jersey.repackaged.com.google.common.util.concurrent.SettableFuture;
19+
import rx.Observable;
20+
import rx.Observable.OnSubscribe;
21+
import rx.Subscriber;
22+
import rx.functions.Action0;
23+
import rx.functions.Action1;
24+
25+
class ResilientConnector implements Connector {
26+
27+
private final Connector delegateConnector;
28+
29+
private final HystrixCommandConfigProvider hystrixCommandConfigProvider;
30+
31+
public ResilientConnector(Client client, Configuration runtimeConfig, Connector delegateConnector) {
32+
this.delegateConnector = delegateConnector;
33+
this.hystrixCommandConfigProvider = initCommandConfigProvider(runtimeConfig);
34+
}
35+
36+
@Override
37+
public ClientResponse apply(final ClientRequest request) {
38+
com.netflix.hystrix.HystrixCommand.Setter setter = hystrixCommandConfigProvider.commandConfig(request);
39+
HystrixCommand<ClientResponse> command = new HystrixCommand<ClientResponse>(setter) {
40+
41+
@Override
42+
protected ClientResponse run() throws Exception {
43+
return delegateConnector.apply(request);
44+
}
45+
};
46+
return command.execute();
47+
}
48+
49+
@Override
50+
public Future<?> apply(final ClientRequest request, final AsyncConnectorCallback callback) {
51+
com.netflix.hystrix.HystrixObservableCommand.Setter setter =
52+
hystrixCommandConfigProvider.observableCommandConfig(request);
53+
HystrixObservableCommand<ClientResponse> observableCommand = new HystrixObservableCommand<ClientResponse>(setter) {
54+
55+
@Override
56+
protected Observable<ClientResponse> construct() {
57+
return Observable.create(new OnSubscribe<ClientResponse>() {
58+
59+
@Override
60+
public void call(Subscriber<? super ClientResponse> observer) {
61+
delegateConnector.apply(request, callback);
62+
}
63+
});
64+
}
65+
};
66+
final SettableFuture<ClientResponse> settableFuture = SettableFuture.create();
67+
OnNext onNext = new OnNext();
68+
OnError onError = new OnError(settableFuture, callback);
69+
OnComplete onComplete = new OnComplete(onNext, settableFuture, callback);
70+
71+
observableCommand.observe().subscribe(onNext, onError, onComplete);
72+
return settableFuture;
73+
}
74+
75+
@Override
76+
public String getName() {
77+
return "Resilient_" + delegateConnector.getName();
78+
}
79+
80+
@Override
81+
public void close() {
82+
delegateConnector.close();
83+
}
84+
85+
private static HystrixCommandConfigProvider initCommandConfigProvider(Configuration runtimeConfig) {
86+
Object value = runtimeConfig.getProperty(ResilientConnectorProvider.HYSTRIX_COMMAND_CONFIG_PROVIDER);
87+
if (value != null) {
88+
return PropertiesHelper.convertValue(value, HystrixCommandConfigProvider.class);
89+
}
90+
return new DefaultHystrixCommandConfigProvider();
91+
}
92+
93+
private static class OnNext implements Action1<ClientResponse> {
94+
95+
private ClientResponse response;
96+
97+
@Override
98+
public void call(ClientResponse response) {
99+
this.response = response;
100+
}
101+
102+
ClientResponse get() {
103+
return this.response;
104+
}
105+
}
106+
107+
private static class OnError implements Action1<Throwable> {
108+
109+
private AsyncConnectorCallback callback;
110+
private SettableFuture<ClientResponse> settableFuture;
111+
112+
OnError(SettableFuture<ClientResponse> settableFuture, AsyncConnectorCallback callback) {
113+
this.settableFuture = settableFuture;
114+
this.callback = callback;
115+
}
116+
117+
@Override
118+
public void call(Throwable failure) {
119+
settableFuture.setException(failure);
120+
callback.failure(failure);
121+
}
122+
}
123+
124+
private static class OnComplete implements Action0 {
125+
126+
private OnNext onNext;
127+
private AsyncConnectorCallback callback;
128+
private SettableFuture<ClientResponse> settableFuture;
129+
130+
OnComplete(OnNext onNext, SettableFuture<ClientResponse> settableFuture, AsyncConnectorCallback callback) {
131+
this.onNext = onNext;
132+
this.settableFuture = settableFuture;
133+
this.callback = callback;
134+
}
135+
136+
@Override
137+
public void call() {
138+
settableFuture.set(onNext.get());
139+
callback.response(onNext.get());
140+
}
141+
}
142+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.glassfish.jersey.resilient.connector;
2+
3+
import javax.ws.rs.client.Client;
4+
import javax.ws.rs.core.Configuration;
5+
6+
import org.glassfish.jersey.client.ClientRequest;
7+
import org.glassfish.jersey.client.spi.Connector;
8+
import org.glassfish.jersey.client.spi.ConnectorProvider;
9+
import org.glassfish.jersey.internal.util.Property;
10+
11+
import com.netflix.hystrix.HystrixCommand;
12+
import com.netflix.hystrix.HystrixObservableCommand;
13+
14+
public class ResilientConnectorProvider implements ConnectorProvider {
15+
16+
@Property
17+
public static final String HYSTRIX_COMMAND_CONFIG_PROVIDER = "jersey.config.client.hystrix.command.config.provider";
18+
19+
private final ConnectorProvider delegateConnectorProvider;
20+
21+
public static interface HystrixCommandConfigProvider {
22+
23+
public String commandName(ClientRequest requestContext);
24+
25+
public HystrixCommand.Setter commandConfig(ClientRequest requestContext);
26+
27+
public HystrixObservableCommand.Setter observableCommandConfig(ClientRequest requestContext);
28+
29+
}
30+
public ResilientConnectorProvider(final ConnectorProvider connectorProvider) {
31+
this.delegateConnectorProvider = connectorProvider;
32+
}
33+
34+
@Override
35+
public Connector getConnector(Client client, Configuration runtimeConfig) {
36+
Connector delegateConnector = delegateConnectorProvider.getConnector(client, runtimeConfig);
37+
return new ResilientConnector(client, runtimeConfig, delegateConnector);
38+
}
39+
40+
}

0 commit comments

Comments
 (0)