Regression 3.0.1 vs 2.15.3: client external DIP
Cette erreur n'arrive pas en 2.15.3, mais arrive en 3.0.1:
13:28:54.526 [pool-1-thread-1] ERROR fr.gouv.vitam.common.retryable.Retryable - [frederic-X510UQ:UnknownRole:42087724] [frederic-X510UQ:UnknownRole:42087724] Retryable='fr.gouv.vitam.common.external.client.AbstractCommonClient$$Lambda$148/0x0000000840375840@ab3b448' - Will retry, attempt '1' in '1' SECONDS. javax.ws.rs.ProcessingException: org.apache.http.conn.HttpHostConnectException: Connect to localhost:8189 [localhost/127.0.0.1] failed: Connexion refusée (Connection refused)
at fr.gouv.vitam.common.external.client.VitamApacheHttpClientEngine.invoke(VitamApacheHttpClientEngine.java:329)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:439)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:61)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.method(ClientInvocationBuilder.java:297)
at fr.gouv.vitam.common.external.client.AbstractCommonClient.lambda$doRequest$1(AbstractCommonClient.java:195)
at fr.gouv.vitam.common.retryable.RetryableOnException.exec(RetryableOnException.java:65)
at fr.gouv.vitam.common.external.client.AbstractCommonClient.doRequest(AbstractCommonClient.java:201)
at fr.gouv.vitam.common.external.client.AbstractCommonClient.make(AbstractCommonClient.java:171)
at fr.gouv.vitam.common.external.client.DefaultClient.make(DefaultClient.java:34)
at fr.gouv.vitam.access.external.client.AdminExternalClientRest.getOperationProcessStatus(AdminExternalClientRest.java:674)
at fr.gouv.vitam.access.external.client.VitamPoolingClient.wait(VitamPoolingClient.java:79)
at fr.gouv.vitam.access.external.client.VitamPoolingClient.wait(VitamPoolingClient.java:144)
at org.waarp.vitam.common.OperationCheck.checkAvailabilityAtr(OperationCheck.java:135)
at org.waarp.vitam.common.OperationCheck.main(OperationCheck.java:110)
at org.waarp.vitam.dip.DipTaskTest.givenErrorWhenCheckKO(DipTaskTest.java:436)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.apache.maven.surefire.junitcore.pc.Scheduler$1.run(Scheduler.java:405)
at org.apache.maven.surefire.junitcore.pc.InvokerStrategy.schedule(InvokerStrategy.java:54)
at org.apache.maven.surefire.junitcore.pc.Scheduler.schedule(Scheduler.java:362)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.apache.maven.surefire.junitcore.pc.Scheduler$1.run(Scheduler.java:405)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to localhost:8189 [localhost/127.0.0.1] failed: Connexion refusée (Connection refused)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:156)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at fr.gouv.vitam.common.external.client.VitamApacheHttpClientEngine.invoke(VitamApacheHttpClientEngine.java:279)
... 48 more
Caused by: java.net.ConnectException: Connexion refusée (Connection refused)
at java.base/java.net.PlainSocketImpl.socketConnect(Native Method)
at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399)
at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242)
at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
at java.base/java.net.Socket.connect(Socket.java:609)
at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:75)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
... 56 more
Plus difficile à trouver la source, mais sans doute similaire à celle de Ingest.
Le port visible est celui généré par Vitam pour le serveur de test Junit (code toujours inspiré des Junit Vitam, ici sur Access pour /dipexport et /dipexport/{id}/dip). Sous v2.15 (et avant), ça fonctionne. A partir de v3.0.1, l'erreur est générée. (aucun changement côté code Waarp)
Avec v2.15.3, il y a aussi l'accès impossible (manifestement lors de l'accès au statut Operation) sur le même port, mais le code est simplement en erreur même exception, mais cette fois le code se poursuit correctement... ??
Donc la différence est ailleurs... (puisque le même non accès au port 8189). Sans doute comme pour Ingest, un contrôle additionnel sur le pooling qui n'existait pas avant ?
Merci pour avoir scindé les issues. Comme pour l'issue associée, serait-il par exemple possible de disposer du code junit qui plante sur la 3.0.1 pour essayer de reproduire l'issue ? Il est également possible qu'un complément de stack trace soit nécessaire, je vous tiendrais au courant sur ce point.
OK, je pense avoir trouvé la raison: changement du comportement du client Vitam.
RequestResponse requestResponse =
client.exportDIP(vitamContext, jsonNode); // client is AccessExternalClient
En cas d'erreur, auparavant, si le serveur retournait une erreur 500 (INTERNAL_SERVER_ERROR), il remontait un
if (!requestResponse.isOk()) { // True since Response is not OK
Et du coup, on obtenait :
logger.error(ERROR_MESSAGE, ISSUE_SINCE_SELECT_PRODUCES_AN_ERROR,
requestResponse);
Soit le log:
17:06:19.324 [DipManager-1] ERROR org.waarp.vitam.dip.DipManager - org.waarp.vitam.dip.DipManager.select(DipManager.java:255) : Issue since Select produces an error
{"httpCode":500,"code":"INTERNAL_SERVER_ERROR","context":"ACCESS_EXTERNAL","state":"code_vitam","message":"Internal Server Error","description":"Internal Server Error"}
Maintenant, il retourne un VitamException (Error with the response, get status: '500' and reason 'Internal Server Error') (fake code)
Soit un log:
17:05:12.613 [DipManager-1] ERROR org.waarp.vitam.dip.DipManager - org.waarp.vitam.dip.DipManager.select(DipManager.java:276) : Issue since Select produces an error
fr.gouv.vitam.common.exception.VitamClientException: Error with the response, get status: '500' and reason 'Internal Server Error'.
at fr.gouv.vitam.access.external.client.AccessExternalClientRest.check(AccessExternalClientRest.java:452)
at fr.gouv.vitam.access.external.client.AccessExternalClientRest.exportDIP(AccessExternalClientRest.java:226)
at org.waarp.vitam.dip.DipManager.select(DipManager.java:236)
at org.waarp.vitam.dip.DipManager.runStep(DipManager.java:189)
at org.waarp.vitam.dip.DipManager.run(DipManager.java:147)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Donc en résumé:
- En cas d'erreur 500, le client maintenant lève une exception VitamClientException au lieu d'un retour normal avec un code 500.
- Ceci est une rupture du contrat (behavior) de l'API Java... et rend incompatible un programme conçu pour la version 2 avec la version 3...
Je vais voir si de mon côté (client de Vitam Client), je peux corriger cela...
Je suppose que pour Ingest c'est assez proche... à suivre...
Pour info, je rechigne à corriger mon code pour prendre en compte ce changement majeur car:
- en version 2.15: une exception VitamClientException n'était levée QUE si une erreur grave (IllegalStateException, VitamClientInternalException) mais pas pour un statut 500
- en version 3.0: une exception est systématiquement levée si non
(SUCCESSFUL.equals(status.getFamily()) || REDIRECTION.equals(status.getFamily()))
Changement important, n'est-il pas ? 404 est aussi du coup une erreur Exception, et ainsi de suite...
Changer un retour normal par une exception qui, de plus, est déjà utilisée pour d'autres cas d'erreur, rend plus complexe la gestion des erreurs pour un client externe (comment fait il la différence entre une erreur temporaire et une erreur définitive, une erreur du client interne et une erreur du serveur externe) ?
Que proposez-vous ?
Note: pour le moment, le fix n'est que temporaire et ne sera sans doute pas "validé" comme merge, c'est plus pour vous montrer les impacts...
Si la réponse est la même de votre côté que pour Ingest:
Certes, mais du coup, c'est un retour en arrière (contrat de fonctionnement). De plus, il est alors impossible pour l'utilisateur du client de connaître la raison (4xx, 5xx, ...) ou de faire une distinction avec une erreur interne du client Vitam (et non de la réponse Serveur).
Du coup, il est impossible de prendre en compte des statuts différents de réponse du serveur et donc de traiter ces erreurs différemment. Ceci est un problème grave selon moi.
Il semble que la 3.0.3 ne fixe pas ces points. Je me trompe ?