firebase / firebase/firebase-admin-java

connection keepAlive does not apply.

Aberta
#880 1 comentário 0 reações 0 responsáveis Ver no GitHub
needs-triage
Linguagem predominante
Java
Estrelas
620
Forks
305
Merge médio
3h 23min
PRs com merge (30d)
1

Descrição

### [REQUIRED] Step 2: Describe your environment

* Operating System version: linux
* Firebase SDK version: firebase-admin-8.1.0.jar
* Library version: 8.1.0.jar
* Firebase Product: Cloud Messaging (auth, database, storage, etc)

### [REQUIRED] Step 3: Describe the problem
We confirmed that keepAlive is applied when using firebase-admin version 6.8.0.
However, after upgrading to firebase-admin 8.1.0, keepAlive is not applied and the connection is immediately disconnected.

#### Steps to reproduce:
firebase-admin 6.8.0 FirebaseMessagingClient.sendSingleRequest()
![image](https://github.com/firebase/firebase-admin-java/assets/5026821/0344f4e8-b2aa-49a4-b76d-508b22c68cfe)
(apache httpclient-4.5.11) ConnectionHolder.releaseConnection() is called due to line 129.
At this time, this.released changes from false to true.
After that, ApiClientUtils.disconnectQuietly(response) -> (apache httpclient-4.5.11) ConnectionHolder.abortConnection() on line 132 is called, but the connection is not disconnected because ConnectionHolder.released = true.
![image](https://github.com/firebase/firebase-admin-java/assets/5026821/8cec24c6-4e52-4c9b-9954-e095daeee24e)
![image](https://github.com/firebase/firebase-admin-java/assets/5026821/67d9df90-b7e5-43cf-acf0-1e7e82ae7275)

However, in firebase-admin 8.1.0, ConnectionHolder.releaseConnection() is not called, but ConnectionHolder.abortConnection() is called, so the connection is disconnected.
![image](https://github.com/firebase/firebase-admin-java/assets/5026821/0896d325-4948-4d2f-8dcd-160e0f3fc2a6)

What happened? How can we make the problem occur?
Establishing connections is expensive. Therefore, recycling connections for a certain period of time can help improve performance. According to what I have checked, the code of the latest version, 9.2.0, is also the same.

#### Relevant Code:

```
private FirebaseMessaging initializeFirebaseMessaging()
throws IOException {
CloseableHttpClient httpClient = newHttpClient(proxyHost, proxyPort);

HttpTransport httpTransport = new ApacheHttpTransport(httpClient);

FirebaseOptions options = FirebaseOptions.builder()
// need credentials etc
.setHttpTransport(httpTransport)
.build();

FirebaseApp.initializeApp(options);
return FirebaseMessaging.getInstance();
}

private CloseableHttpClient newHttpClient(String proxyHost, int proxyPort) {
HttpClientBuilder httpClientBuilder = ApacheHttpTransport.newDefaultHttpClientBuilder()
.evictExpiredConnections()
.setKeepAliveStrategy(
new CustomConnectionKeepAliveStrategy(
TimeUnit.MINUTES.toMillis(3)))
.setConnectionTimeToLive(10, TimeUnit.MINUTES)
.setDefaultRequestConfig(requestConfig())
.disableCookieManagement();
return httpClientBuilder.build();
}

public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {

public static final CustomConnectionKeepAliveStrategy INSTANCE =
new CustomConnectionKeepAliveStrategy(TimeUnit.SECONDS.toMillis(50),
DefaultConnectionKeepAliveStrategy.INSTANCE);

public static final ConnectionKeepAliveStrategy NO_KEEPALIVE = (response, context) -> 0;

private static final long KEEP_ALIVE_SAFE_GAP = 500L;
private final ConnectionKeepAliveStrategy defaultConnectionKeepAliveStrategy;
private final long defaultKeepAliveTimeoutInMillis;

public CustomConnectionKeepAliveStrategy(long defaultKeepAliveTimeoutInMillis) {
this(defaultKeepAliveTimeoutInMillis, DefaultConnectionKeepAliveStrategy.INSTANCE);
}

public CustomConnectionKeepAliveStrategy(long defaultKeepAliveTimeoutInMillis,
ConnectionKeepAliveStrategy defaultConnectionKeepAliveStrategy) {
Args.notNegative(defaultKeepAliveTimeoutInMillis, "defaultKeepAliveTimeoutInMillis");
Args.notNull(defaultConnectionKeepAliveStrategy, "defaultConnectionKeepAliveStrategy");
this.defaultKeepAliveTimeoutInMillis = defaultKeepAliveTimeoutInMillis;
this.defaultConnectionKeepAliveStrategy = defaultConnectionKeepAliveStrategy;
}

public static long adjustKeepAliveTimeout(long keepAliveTimeoutInMillis) {
return Math.max(0L, (keepAliveTimeoutInMillis - KEEP_ALIVE_SAFE_GAP));
}

@Override
public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
long keepAliveDuration = defaultConnectionKeepAliveStrategy.getKeepAliveDuration(response, context);
if (keepAliveDuration == -1L) {
return defaultKeepAliveTimeoutInMillis;
}
if (keepAliveDuration > 0L) {
return adjustKeepAliveTimeout(keepAliveDuration);
}
return keepAliveDuration;
}
```

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Comece comparando o comportamento de FirebaseMessagingClient.sendSingleRequest() no firebase-admin 6.8.0 e 8.1.0, concentrando-se em ApiClientUtils.disconnectQuietly(response) e nas chamadas de Apache HttpClient ConnectionHolder descritas no relatório. Reproduza o ciclo de vida da conexão com a estratégia personalizada de keep-alive fornecida e verifique se as conexões são mantidas e recicladas de acordo com as durações configuradas.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
java
Domínio
networking
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Estagnada
Clareza
Precisa de esclarecimento
Facilidade para iniciantes
30/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.