Automatic reconnect to GAE when the connection is dropped

The connection to GAE is not persistent and can drop. Reconnect when that happens, as long as the connection from the client is still active.

We need to consider the fact that while a reconnection is happening, the client may be sending requests that was relayed to the old connection, which is not going through. In that case these requests are queued and will be retried when the new connection is available.

Since we are no longer tying the lifecycles of the two connections, we cannot automatically terminate one when another is terminated. Also we need to explicitly control how WHOIS connection is terminated, not depending on the HTTP connection header.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=207335498
This commit is contained in:
jianglai 2018-08-03 15:37:21 -07:00
parent 0b8e7498e0
commit 4ff77fb370
8 changed files with 203 additions and 79 deletions

View file

@ -17,6 +17,7 @@ package google.registry.proxy;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.proxy.TestUtils.makeWhoisHttpRequest;
import static google.registry.proxy.TestUtils.makeWhoisHttpResponse;
import static google.registry.testing.JUnitBackports.assertThrows;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.stream.Collectors.joining;
import static org.junit.Assert.fail;
@ -26,6 +27,7 @@ import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import java.nio.channels.ClosedChannelException;
import java.util.stream.Stream;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -53,7 +55,7 @@ public class WhoisProtocolModuleTest extends ProtocolModuleTest {
PROXY_CONFIG.whois.relayHost,
PROXY_CONFIG.whois.relayPath,
TestModule.provideFakeAccessToken().get());
assertThat(expectedRequest).isEqualTo(actualRequest);
assertThat(actualRequest).isEqualTo(expectedRequest);
assertThat(channel.isActive()).isTrue();
// Nothing more to read.
assertThat((Object) channel.readInbound()).isNull();
@ -88,7 +90,7 @@ public class WhoisProtocolModuleTest extends ProtocolModuleTest {
PROXY_CONFIG.whois.relayHost,
PROXY_CONFIG.whois.relayPath,
TestModule.provideFakeAccessToken().get());
assertThat(expectedRequest1).isEqualTo(actualRequest1);
assertThat(actualRequest1).isEqualTo(expectedRequest1);
// No more message at this point.
assertThat((Object) channel.readInbound()).isNull();
// More inbound bytes, but no newline.
@ -102,7 +104,7 @@ public class WhoisProtocolModuleTest extends ProtocolModuleTest {
PROXY_CONFIG.whois.relayHost,
PROXY_CONFIG.whois.relayPath,
TestModule.provideFakeAccessToken().get());
assertThat(expectedRequest2).isEqualTo(actualRequest2);
assertThat(actualRequest2).isEqualTo(expectedRequest2);
// The third message is not complete yet.
assertThat(channel.isActive()).isTrue();
assertThat((Object) channel.readInbound()).isNull();
@ -126,26 +128,23 @@ public class WhoisProtocolModuleTest extends ProtocolModuleTest {
assertThat(channel.writeOutbound(response)).isTrue();
ByteBuf outputBuffer = channel.readOutbound();
assertThat(outputBuffer.toString(US_ASCII)).isEqualTo(outputString);
assertThat(channel.isActive()).isTrue();
assertThat(channel.isActive()).isFalse();
// Nothing more to write.
assertThat((Object) channel.readOutbound()).isNull();
}
@Test
public void testSuccess_parseMultipleOutboundHttpResponse() {
public void testFailure_parseOnlyFirstFromMultipleOutboundHttpResponse() {
String outputString1 = "line1\r\nline2\r\n";
String outputString2 = "line3\r\nline4\r\nline5\r\n";
FullHttpResponse response1 = makeWhoisHttpResponse(outputString1, HttpResponseStatus.OK);
FullHttpResponse response2 = makeWhoisHttpResponse(outputString2, HttpResponseStatus.OK);
assertThat(channel.writeOutbound(response1, response2)).isTrue();
assertThrows(ClosedChannelException.class, () -> channel.writeOutbound(response1, response2));
// First Http response parsed
ByteBuf outputBuffer1 = channel.readOutbound();
assertThat(outputBuffer1.toString(US_ASCII)).isEqualTo(outputString1);
// Second Http response parsed
ByteBuf outputBuffer2 = channel.readOutbound();
assertThat(outputBuffer2.toString(US_ASCII)).isEqualTo(outputString2);
assertThat(channel.isActive()).isTrue();
// Nothing more to write.
// Second Http response not parsed because the connection is closed.
assertThat(channel.isActive()).isFalse();
assertThat((Object) channel.readOutbound()).isNull();
}