Improve gateway reliability and dashboard docs
This commit is contained in:
+21
-18
@@ -334,25 +334,28 @@ public final class MxGatewayCli implements Callable<Integer> {
|
||||
var session = client.openSession(OpenSessionRequest.newBuilder()
|
||||
.setClientSessionName(clientName)
|
||||
.build());
|
||||
MxGatewayCliSession cliSession = client.session(session.getSessionId());
|
||||
int serverHandle = cliSession.register(clientName);
|
||||
int itemHandle = cliSession.addItem(serverHandle, item);
|
||||
cliSession.advise(serverHandle, itemHandle);
|
||||
if (json) {
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
output.put("command", "smoke");
|
||||
output.put("options", common.redactedJsonMap());
|
||||
output.put("sessionId", session.getSessionId());
|
||||
output.put("serverHandle", serverHandle);
|
||||
output.put("itemHandle", itemHandle);
|
||||
client.out().println(jsonObject(output));
|
||||
} else {
|
||||
client.out().printf(
|
||||
"session=%s server=%d item=%d%n", session.getSessionId(), serverHandle, itemHandle);
|
||||
try {
|
||||
MxGatewayCliSession cliSession = client.session(session.getSessionId());
|
||||
int serverHandle = cliSession.register(clientName);
|
||||
int itemHandle = cliSession.addItem(serverHandle, item);
|
||||
cliSession.advise(serverHandle, itemHandle);
|
||||
if (json) {
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
output.put("command", "smoke");
|
||||
output.put("options", common.redactedJsonMap());
|
||||
output.put("sessionId", session.getSessionId());
|
||||
output.put("serverHandle", serverHandle);
|
||||
output.put("itemHandle", itemHandle);
|
||||
client.out().println(jsonObject(output));
|
||||
} else {
|
||||
client.out().printf(
|
||||
"session=%s server=%d item=%d%n", session.getSessionId(), serverHandle, itemHandle);
|
||||
}
|
||||
} finally {
|
||||
client.closeSession(CloseSessionRequest.newBuilder()
|
||||
.setSessionId(session.getSessionId())
|
||||
.build());
|
||||
}
|
||||
client.closeSession(CloseSessionRequest.newBuilder()
|
||||
.setSessionId(session.getSessionId())
|
||||
.build());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+12
-5
@@ -105,13 +105,20 @@ public final class MxEventStream implements Iterator<MxEvent>, AutoCloseable {
|
||||
private void offer(Object value) {
|
||||
Objects.requireNonNull(value, "value");
|
||||
if (value == END) {
|
||||
queue.offer(value);
|
||||
if (!queue.offer(value)) {
|
||||
queue.clear();
|
||||
queue.offer(value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
queue.put(value);
|
||||
} catch (InterruptedException error) {
|
||||
Thread.currentThread().interrupt();
|
||||
if (!queue.offer(value)) {
|
||||
ClientCallStreamObserver<StreamEventsRequest> stream = requestStream;
|
||||
if (stream != null) {
|
||||
stream.cancel("client event stream queue overflowed", null);
|
||||
}
|
||||
queue.clear();
|
||||
queue.offer(new MxGatewayException("gateway stream events queue overflowed"));
|
||||
queue.offer(END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-4
@@ -63,7 +63,7 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
}
|
||||
|
||||
public MxAccessGatewayGrpc.MxAccessGatewayStub rawAsyncStub() {
|
||||
return withDeadline(asyncStub);
|
||||
return asyncStub;
|
||||
}
|
||||
|
||||
public MxGatewaySession openSession(OpenSessionRequest request) {
|
||||
@@ -140,14 +140,14 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
|
||||
public MxEventStream streamEvents(StreamEventsRequest request) {
|
||||
MxEventStream stream = new MxEventStream(16);
|
||||
rawAsyncStub().streamEvents(request, stream.observer());
|
||||
withStreamDeadline(rawAsyncStub()).streamEvents(request, stream.observer());
|
||||
return stream;
|
||||
}
|
||||
|
||||
public MxGatewayEventSubscription streamEventsAsync(
|
||||
StreamEventsRequest request, StreamObserver<MxEvent> observer) {
|
||||
MxGatewayEventSubscription subscription = new MxGatewayEventSubscription();
|
||||
rawAsyncStub().streamEvents(request, subscription.wrap(observer));
|
||||
withStreamDeadline(rawAsyncStub()).streamEvents(request, subscription.wrap(observer));
|
||||
return subscription;
|
||||
}
|
||||
|
||||
@@ -161,7 +161,9 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
public void closeAndAwaitTermination() throws InterruptedException {
|
||||
if (ownedChannel != null) {
|
||||
ownedChannel.shutdown();
|
||||
ownedChannel.awaitTermination(options.connectTimeout().toMillis(), TimeUnit.MILLISECONDS);
|
||||
if (!ownedChannel.awaitTermination(options.connectTimeout().toMillis(), TimeUnit.MILLISECONDS)) {
|
||||
ownedChannel.shutdownNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +201,13 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
return stub.withDeadlineAfter(options.callTimeout().toNanos(), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
private <T extends io.grpc.stub.AbstractStub<T>> T withStreamDeadline(T stub) {
|
||||
if (options.streamTimeout() == null || options.streamTimeout().isNegative()) {
|
||||
return stub;
|
||||
}
|
||||
return stub.withDeadlineAfter(options.streamTimeout().toNanos(), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
private static <T> CompletableFuture<T> toCompletable(com.google.common.util.concurrent.ListenableFuture<T> source) {
|
||||
CompletableFuture<T> target = new CompletableFuture<>();
|
||||
Futures.addCallback(
|
||||
@@ -219,6 +228,11 @@ public final class MxGatewayClient implements AutoCloseable {
|
||||
}
|
||||
},
|
||||
MoreExecutors.directExecutor());
|
||||
target.whenComplete((ignoredResult, ignoredError) -> {
|
||||
if (target.isCancelled()) {
|
||||
source.cancel(true);
|
||||
}
|
||||
});
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -15,6 +15,7 @@ public final class MxGatewayClientOptions {
|
||||
private final String serverNameOverride;
|
||||
private final Duration connectTimeout;
|
||||
private final Duration callTimeout;
|
||||
private final Duration streamTimeout;
|
||||
|
||||
private MxGatewayClientOptions(Builder builder) {
|
||||
endpoint = requireText(builder.endpoint, "endpoint");
|
||||
@@ -24,6 +25,7 @@ public final class MxGatewayClientOptions {
|
||||
serverNameOverride = builder.serverNameOverride == null ? "" : builder.serverNameOverride;
|
||||
connectTimeout = builder.connectTimeout == null ? DEFAULT_CONNECT_TIMEOUT : builder.connectTimeout;
|
||||
callTimeout = builder.callTimeout == null ? DEFAULT_CALL_TIMEOUT : builder.callTimeout;
|
||||
streamTimeout = builder.streamTimeout;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
@@ -62,6 +64,10 @@ public final class MxGatewayClientOptions {
|
||||
return callTimeout;
|
||||
}
|
||||
|
||||
public Duration streamTimeout() {
|
||||
return streamTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MxGatewayClientOptions{"
|
||||
@@ -82,6 +88,8 @@ public final class MxGatewayClientOptions {
|
||||
+ connectTimeout
|
||||
+ ", callTimeout="
|
||||
+ callTimeout
|
||||
+ ", streamTimeout="
|
||||
+ streamTimeout
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -100,6 +108,7 @@ public final class MxGatewayClientOptions {
|
||||
private String serverNameOverride;
|
||||
private Duration connectTimeout;
|
||||
private Duration callTimeout;
|
||||
private Duration streamTimeout;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
@@ -139,6 +148,11 @@ public final class MxGatewayClientOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder streamTimeout(Duration value) {
|
||||
streamTimeout = Objects.requireNonNull(value, "streamTimeout");
|
||||
return this;
|
||||
}
|
||||
|
||||
public MxGatewayClientOptions build() {
|
||||
return new MxGatewayClientOptions(this);
|
||||
}
|
||||
|
||||
+6
@@ -4,17 +4,22 @@ import io.grpc.stub.ClientCallStreamObserver;
|
||||
import io.grpc.stub.ClientResponseObserver;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import mxaccess_gateway.v1.MxaccessGateway.MxEvent;
|
||||
import mxaccess_gateway.v1.MxaccessGateway.StreamEventsRequest;
|
||||
|
||||
public final class MxGatewayEventSubscription implements AutoCloseable {
|
||||
private final AtomicReference<ClientCallStreamObserver<StreamEventsRequest>> requestStream = new AtomicReference<>();
|
||||
private final AtomicBoolean cancelled = new AtomicBoolean();
|
||||
|
||||
ClientResponseObserver<StreamEventsRequest, MxEvent> wrap(StreamObserver<MxEvent> observer) {
|
||||
return new ClientResponseObserver<>() {
|
||||
@Override
|
||||
public void beforeStart(ClientCallStreamObserver<StreamEventsRequest> stream) {
|
||||
requestStream.set(stream);
|
||||
if (cancelled.get()) {
|
||||
stream.cancel("client cancelled event stream", null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,6 +40,7 @@ public final class MxGatewayEventSubscription implements AutoCloseable {
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
cancelled.set(true);
|
||||
ClientCallStreamObserver<StreamEventsRequest> stream = requestStream.get();
|
||||
if (stream != null) {
|
||||
stream.cancel("client cancelled event stream", null);
|
||||
|
||||
Reference in New Issue
Block a user