2

J'ai une application Spring Boot très simple, qui fournit quelques points de terminaison reposants et cela est supposé conduire un fichier sftp téléchargé sur un serveur sftp. Mon exigence est que s'il y a plus d'un fichier, les fichiers doivent être mis en file d'attente. Je m'attendais à réaliser cela avec le comportement par défaut du flux de travail d'intégration de Spring sftp, car j'ai lu que DirectChannel met automatiquement en file d'attente les fichiers. Pour tester le comportement, procédez comme suit:Points de terminaison REST dans Spring Intégration faire des canaux de messagerie multithread

  1. Envoyez un fichier volumineux en bloquant le canal pendant un certain temps en appelant un noeud final.
  2. Envoyez un fichier plus petit en appelant un noeud final.

Résultat attendu: le plus petit fichier est mis en file d'attente sur un canal et est traité après la fin du chargement du plus gros fichier. Résultat: Une nouvelle connexion au serveur sftp est ouverte et le fichier le plus petit y est transféré sans être mis en file d'attente, tandis que le fichier plus volumineux continue la transmission.

Il y a deux fichiers dans mon application:

DemoApplication.java

@SpringBootApplication 
@IntegrationComponentScan 
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) 
public class DemoApplication { 

    public static void main(String[] args) { 
     SpringApplication.run(DemoApplication.class, args); 
    } 

    @Bean 
    public SessionFactory<LsEntry> sftpSessionFactory() { 
     DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true); 
     factory.setHost("localhost"); 
     factory.setPort(22); 
     factory.setUser("tester"); 
     factory.setPassword("password"); 
     factory.setAllowUnknownKeys(true); 
     return factory; 
    } 

    @Bean 
    @ServiceActivator(inputChannel = "toSftpChannel") 
    public MessageHandler handler() { 
     SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory()); 
     handler.setRemoteDirectoryExpression(new LiteralExpression("/")); 
     return handler; 
    } 

    @MessagingGateway 
    public interface MyGateway { 

     @Gateway(requestChannel = "toSftpChannel") 
     void sendToSftp(File file); 
    } 
} 

DemoController.java

@RestController 
public class DemoController { 

    @Autowired 
    MyGateway gateway; 

    @RequestMapping("/sendFile") 
    public void sendFile() { 
     File file = new File("C:/smallFile.txt"); 
     gateway.sendToSftp(file); 
    } 

    @RequestMapping("/sendBigFile") 
    public void sendBigFile() { 
     File file = new File("D:/bigFile.zip"); 
     gateway.sendToSftp(file); 
    } 
} 

Je suis un débutant complet au printemps et je ne suis pas sûr Entièrement que mes canaux sftp soient créés correctement ici, je suppose qu'un nouveau sera créé chaque fois que je fais un appel sendToSftp. Toute aide sur la façon d'atteindre le comportement de file d'attente dans ce cas serait appréciée.

Répondre

2

Vous n'avez pas de file d'attente ici car chaque requête HTTP est effectuée dans son propre thread. Bon, vous pouvez peut-être y faire la queue quand le pool de threads http est épuisé, mais cela ne ressemble pas à votre simple cas d'utilisation avec seulement deux requêtes.

De toute façon, vous pouvez obtenir un comportement de file d'attente, mais vous devez déclarer votre toSftpChannel en tant que bean QueueChannel. De cette façon, le processus en aval sera toujours exécuté sur le même thread et le message suivant est extrait de la file d'attente exactement après le premier. Pour plus d'informations, voir Reference Manual pour plus d'informations.

MISE À JOUR

Puisque vous utilisez FtpMessageHandler qui est le composant à sens unique, mais vous avez encore une réponse aux méthodes du contrôleur MVC, seule la façon de le faire est d'avoir une méthode @Gateway avec non void retour et bien sûr nous devons envoyer la réponse en quelque sorte.

A cet effet, je vous suggère d'utiliser PublishSubscribeChannel:

@Bean 
@BridgeTo 
public MessageChannel toSftpChannel() { 
    return new PublishSubscribeChannel(); 
} 

@Bean 
@ServiceActivator(inputChannel = "toSftpChannel") 
@Order(0) 
public MessageHandler handler() { 
    SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory()); 
    handler.setRemoteDirectoryExpression(new LiteralExpression("/")); 
    return handler; 
} 

De cette façon, nous avons deux abonnés au toSftpChannel. Avec le @Order(0), nous nous assurons que @ServiceActivator est le premier abonné car nous devons d'abord effectuer un transfert SFTP. Avec le @BridgeTo nous ajoutons un second BridgeHandler au même PublishSubscribeChannel.Son but est simplement d'obtenir un en-tête replyChannel et d'envoyer le message de demande ici. Puisque nous n'utilisons aucun threading, le BridgeHandler sera exécuté exactement après la fin du transfert au SFTP.

Bien sûr, au lieu de BridgeHandler vous pouvez avoir toute autre @ServiceActivator ou @Transfromer pour revenir comme une réponse non une demande File, mais rien d'autre. Par exemple:

@ServiceActivator(inputChannel = "toSftpChannel") 
@Order(1) 
public String transferComplete(File payload) { 
    return "The SFTP transfer complete for file: " + payload; 
} 
+0

Salut, j'ai donc une question à ce sujet. Comment puis-je faire envoyer à sendToSftp l'état du transfert? J'ai essayé de changer void en String ou object, en ajoutant des canaux de réponse ou un canal d'erreur à la passerelle de messagerie sans résultat, une aide serait très appréciée – user2334207

+0

Voir une mise à jour dans ma réponse. –

+0

Comment puis-je capturer des exceptions? J'essaye de contacter soit un serveur ou un dossier non existant sans autorisations ou alors et obtenir une trace de pile massive qui semble montrer une exception MessagingException au sommet. J'ai ajouté MessagingException sur sendToSftp dans la passerelle et entouré avec try catch dans le DemoController, mais il semble que sendToSftp ne retourne pas du tout si une exception se produit – user2334207