2009-07-13 6 views
1

ModifierComment mettre fin CXF appel webservice dans les mises en œuvre à une annulation

Cette question est passé par quelques itérations maintenant, alors ne hésitez pas à regarder à travers les révisions pour voir des informations générales sur l'histoire et les choses a essayé.


J'utilise un CompletionService avec un ExecutorService et callable, appeler simultanément le un certain nombre de fonctions sur quelques webservices différentes par le code généré CXF .. Ces services contribuent différentes informations vers un ensemble unique d'informations que j'utilise pour mon projet. Les services peuvent toutefois ne pas répondre pendant une période prolongée sans exception, prolongeant ainsi l'attente de l'ensemble d'informations. Pour contrer cela, j'exécute simultanément tous les appels de service et, après quelques minutes, je souhaite terminer tous les appels qui ne sont pas encore terminés, et de préférence consigner ceux qui n'ont pas encore été effectués depuis l'intérieur du appelable ou en lançant une exception détaillée.

Voici un code très simplifié pour illustrer ce que je fais déjà:

private Callable<List<Feature>> getXXXFeatures(final WiwsPortType port, 
final String accessionCode) { 
    return new Callable<List<Feature>>() { 
     @Override 
     public List<Feature> call() throws Exception { 
      List<Feature> features = new ArrayList<Feature>(); 
      //getXXXFeatures are methods of the WS Proxy 
      //that can take anywhere from second to never to return 
      for (RawFeature raw : port.getXXXFeatures(accessionCode)) { 
       Feature ft = convertFeature(raw); 
       features.add(ft); 
      } 
      if (Thread.currentThread().isInterrupted()) 
       log.error("XXX was interrupted"); 
      return features; 
     } 
    }; 
} 

Et le code qui commence simultanément les appels WS:

WiwsPortType port = new Wiws().getWiws(); 
List<Future<List<Feature>>> ftList = new ArrayList<Future<List<Feature>>>(); 
//Counting wrapper around CompletionService, 
    //so I could implement ccs.hasRemaining() 
CountingCompletionService<List<Feature>> ccs = 
     new CountingCompletionService<List<Feature>>(threadpool); 
ftList.add(ccs.submit(getXXXFeatures(port, accessionCode))); 
ftList.add(ccs.submit(getYYYFeatures(port accessionCode))); 
ftList.add(ccs.submit(getZZZFeatures(port, accessionCode))); 

List<Feature> allFeatures = new ArrayList<Feature>(); 
while (ccs.hasRemaining()) { 
      //Low for testing, eventually a little more lenient 
    Future<List<Feature>> polled = ccs.poll(5, TimeUnit.SECONDS); 
    if (polled != null) 
     allFeatures.addAll(polled.get()); 
    else { 
     //Still jobs remaining, but unresponsive: Cancel them all 
     int jobsCanceled = 0; 
     for (Future<List<Feature>> job : ftList) 
      if (job.cancel(true)) 
       jobsCanceled++; 
     log.error("Canceled {} feature jobs because they took too long", 
         jobsCanceled); 
     break; 
    } 
} 

Le problème que je vais avoir avec ce code est que les Callables ne sont pas réellement annulés en attendant le port.getXXXFeatures (...) pour retourner, mais en quelque sorte continuer à fonctionner. Comme vous pouvez le voir à partir des instructions if (Thread.currentThread().isInterrupted()) log.error("XXX was interrupted");, l'indicateur interrompu est défini après le retour de port.getFeatures, il n'est disponible qu'une fois l'appel de Webservice terminé, au lieu d'être interrompu lorsque j'ai appelé Annuler.

Quelqu'un peut-il me dire ce que je fais mal et comment je peux arrêter l'appel Cservice Web de CXF après une période de temps donnée, et enregistrer cette information dans mon application?

Meilleures salutations, Tim

+0

Pour intercepter l'annulation à l'intérieur, utilisez la méthode isCancelled(). Votre appel d'annulation devrait provoquer InterruptedException à l'intérieur aussi si vous êtes bloqué sur une attente/IO. – akarnokd

+0

isCancelled() est seulement disponible sur le Future, alors que mon code réside dans le Callable, de sorte que la première ligne ne fonctionnera pas .. Quant à la deuxième ligne: J'ai essayé (mais comme je l'ai dit, mal) d'attraper n'importe quel type de exception dans le Callable, mais était jusqu'ici incapable de le faire .. La fermeture de toutes les lignes dans appel() dans un bloc try/catch pour InterruptedException échoue en raison d'une exception catch block inaccessible car l'exception n'est jamais levée du corps de l'instruction try . (Ou si Eclipse dit;)) Y a-t-il des trucs laids de la classe de Thread redoutée qui pourraient aider ici? – Tim

+1

Cela devrait être le cas, car l'annulation provoque IntExc * une certaine * opération de blocage. J'ai cependant eu des problèmes avec cette hypothèse: tout blocage n'est pas interruptible de cette façon - je pense que synchronized() est un tel exemple (utilisé fréquemment dans les libs). Une option kill serait d'accéder d'une manière ou d'une autre à l'opération d'E/S sous-jacente et d'utiliser un close() asynchrone dessus. Si vous étendez FutureTask, vous gagnez des options Callable et Future, avez-vous essayé? – akarnokd

Répondre

2

Edit 3 de réponse Nouveau.

Je vois ces options:

  • Postez votre problème sur le CXF Apache demande de fonctionnalité
  • Fix ACXF vous et exposer certaines fonctionnalités.
  • Rechercher des options pour le soutien d'appel asynchrone WS au sein de l'Apache CXF
  • envisager de passer à un autre fournisseur de WS (JAX-WS?)
  • Est-ce que WS-vous appeler à l'aide API RESTful si le service supporte (par exemple simple Requête HTTP avec paramètres)
  • Pour les experts: utilisez des threads/groupes de threads réels et supprimez les threads avec des méthodes non orthodoxes.
+0

Désolé mais comment cela fonctionnerait? Vous ne pouvez pas simplement «annuler» le Callable .. Vous pouvez seulement annuler le * Future * retourné lorsque vous soumettez le Callable .. Je ne vois pas comment je serais en mesure d'obtenir l'url du Callable une fois qu'il est perdu après Je le soumets à l'exécuteur. – Tim

+0

Oh, désolé, vous avez raison. J'y penserai à nouveau. – akarnokd

+0

Reformulé la question car la journalisation n'est plus le problème: Le problème est que les appels de service web ne sont pas annulés en premier lieu! Merci pour l'aide jusqu'ici, laisse voir quelles nouvelles réponses cette reformulation apporte .. – Tim

1

Les CXF docs ont des instructions pour le réglage du délai d'attente de lecture sur le HttpURLConnection: http://cwiki.apache.org/CXF20DOC/client-http-transport-including-ssl-support.html

Ce serait probablement répondre à vos besoins. Si le serveur ne répond pas à temps, une exception est déclenchée et l'appel recevrait l'exception. (sauf qu'il y a un bug où PEUT se bloquer à la place Je ne me souviens pas si cela a été corrigé pour 2.2.2 ou si c'est juste dans les SNAPSHOTS maintenant.)

Questions connexes