En développant en Java une méthode asynchrone avec un type de retour CompletableFuture
, nous nous attendons à ce que le CF résultant se termine normalement ou exceptionnellement selon que cette méthode réussit ou échoue.
Cependant, considérez par exemple que ma méthode écrit dans un AsynchronousChannel
et a obtenu une exception ouvrant ce canal. Il n'a même pas commencé à écrire. Donc, dans ce cas, je tente simplement de laisser l'exception couler vers l'appelant. Est-ce correct?
Bien que l'appelant devra gérer 2 scénarios d'échec: 1) exception, ou 2) promesse rejetée.
Ou bien ma méthode doit-elle intercepter cette exception et renvoyer une promesse rejetée à la place?
3 Réponses :
Je pense que les deux sont des designs valables. Datastax a en fait commencé sa conception avec la première approche, où l'emprunt d'une connexion était bloquant, et est passé au modèle entièrement asynchrone ( https://docs.datastax.com/en/developer/java-driver/3.5/upgrade_guide/#3-0-4 ) p >
En tant qu'utilisateur du pilote java datastax, j'étais très satisfait du correctif, car il a changé l'API pour être vraiment non bloquant (même ouvrir un canal, dans votre exemple, a un coût).
Mais je ne pense pas qu'il y ait du bien et du mal ici ...
Cela ne fait pas une grande différence du point de vue des appelants. Dans les deux cas, la cause de l'exception sera visible, qu'elle soit lancée depuis la méthode ou en appelant get () sur le futur complet.
Je dirais peut-être qu'une exception levée par le futur complétable devrait être une exception du calcul asynchrone et ne pas manquer de démarrer ce calcul.
IMO, option 1) rend l'API plus difficile à utiliser car il y aura deux chemins différents pour communiquer les erreurs:
Le programmeur doit maintenant s'assurer que ces deux chemins sont correctement gérés, au lieu d'un seul.
Il est également intéressant d'observer que le comportement pour C # et Javascript est de toujours signaler les exceptions lancées dans le corps d'une fonction async
via la Task
/ Promise
renvoyée, même pour les exceptions levées avant le premier wait , et jamais en terminant l'appel de fonction
async
par une exception.
Il en va de même pour les coroutines de Kotlin, même en utilisant le code Unconfined > dispatcher
6 [main] INFO SynchronousExceptionExamples - before launch 73 [main @coroutine#1] INFO SynchronousExceptionExamples - before throw (...) 90 [main] INFO SynchronousExceptionExamples - after launch
produira
class SynchronousExceptionExamples { @Test fun example() { log.info("before launch") val job = GlobalScope.launch(Dispatchers.Unconfined) { log.info("before throw") throw Exception("an-error") } log.info("after launch") Thread.sleep(1000) assertTrue(job.isCancelled) } }
Notez que l'exception se produit dans le fil de discussion principal
, cependant le lancement
se termine par un Job
approprié .