sendBlocking se bloque jusqu'à ce qu'il expire

Symptôme

Vous avez basculé une opération en mode bloquant avec BlockingMessageGateway, et maintenant la coroutine ne reprend jamais en cas d'échec — elle reste bloquée jusqu'à ce qu'elle lance une TimeoutCancellationException. Les opérations réussies fonctionnent correctement ; seules les erreurs provoquent un blocage. Une connexion ou un paiement qui devrait retourner une erreur se contente de provoquer un délai d'attente.

Cause

sendBlocking reprend lorsque un message du type exact que vous attendiez arrive. Si vous attendez le sous-type de succès (par exemple SuccessRetailerLoginResponse) et que l'opération échoue, l'échec arrive sous un type différent (ErrorRetailerLoginResponse) — qui ne correspond jamais à ce que vous attendiez. La passerelle continue d'attendre, et votre coroutine reste bloquée jusqu'à ce que le délai d'attente expire.

La réponse d'échec a bien été livrée. Vous n'écoutiez simplement pas son type.

Correction

Attendez le super-type scellé, pas un sous-type, puis effectuez un branchement avec when :

// FAUX — reprend uniquement en cas de succès ; chaque échec devient un délai d'attente
val r: SuccessRetailerLoginResponse = gateway.sendBlocking { clientSDK.sendLoginRequest() }

// CORRECT — reprend en cas de succès OU d'erreur
val r: RetailerLoginResponse = gateway.sendBlocking(timeoutMillis = 30000) {
    clientSDK.sendLoginRequest()
}
when (r) {
    is SuccessRetailerLoginResponse -> { /* ok */ }
    is ErrorRetailerLoginResponse   -> { /* gérer l'échec */ }
}

La même règle s'applique à chaque opération : attendez RetailerPaymentResponse, RetailerReversalResponse, etc. — le super-type — et effectuez le branchement ensuite. Le super-type couvre tous les résultats, donc à la fois le succès et l'échec font reprendre votre coroutine.

N'oubliez pas que le paiement a un troisième résultat, PartialRetailerPaymentResponse. Attendre RetailerPaymentResponse le capture ; attendre uniquement le sous-type succès manquerait à la fois les cas d'erreur et partiels.

Toujours un délai d'attente après correction du type ?

Si vous attendez le super-type et que cela expire encore, c'est qu'une réponse n'arrive vraiment pas — vérifiez que la passerelle reçoit bien chaque message (gateway.onNewMessage(message) dans votre intercepteur), que vous avez une session active (voir Cycle de vie de la session et de la connexion), et que le délai d'attente est suffisamment long pour l'opération. Gérez toujours la TimeoutCancellationException quoi qu'il arrive — un vrai délai d'attente est lui-même une condition à laquelle votre application doit réagir.

Articles liés

  • Comment fonctionne le modèle de message — l'explication complète du modèle de super-type.
  • Cycle de vie de la session et de la connexion — une session manquante produit également aucune réponse.