FtpStreamingMessageSource - 失败时重试

时间:2017-06-22 13:04:01

标签: java spring ftp spring-integration

我已经为这个bean配置了spring集成:

private static final Pattern FILE_PATTERN = Pattern.compile("<pattern>");

@Bean
public SessionFactory<FTPFile> ftpSessionFactory(){
    DefaultFtpSessionFactory factory = new DefaultFtpSessionFactory();
    factory.setHost("localhost");
    factory.setPort(21);
    factory.setUsername("root");
    factory.setPassword("123456");
    factory.setClientMode(FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE);
    return new CachingSessionFactory<>(factory);
}

@Bean
public ConcurrentMetadataStore metadataStore(){
    PropertiesPersistingMetadataStore  store = new PropertiesPersistingMetadataStore();
    store.setFileName("ftpStore.properties");
    return store;
}

@Bean(destroyMethod = "close")
public DataSource selectDataSource(){
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setJdbcUrl("jdbc:mysql://10.10.10.10:33306/csv");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    return dataSource;
}

@Bean
public PlatformTransactionManager transactionManager(){
    return new DataSourceTransactionManager(selectDataSource());
}

@Bean
public TransactionSynchronizationFactory synchronizationFactory(){
    return new DefaultTransactionSynchronizationFactory(new TransactionSynchronizationProcessor() {
        @Override
        public void processBeforeCommit(IntegrationResourceHolder integrationResourceHolder) {
            int x = 22; //???
        }

        @Override
        public void processAfterCommit(IntegrationResourceHolder integrationResourceHolder) {
            int x = 22; //???
        }

        @Override
        public void processAfterRollback(IntegrationResourceHolder integrationResourceHolder) {
            int x = 22; //???
        }
    });
}

@Bean
public PollerMetadata pollerMetadata(PlatformTransactionManager transactionManager){
    PeriodicTrigger trigger = new PeriodicTrigger(5000);
    trigger.setFixedRate(true);

    MatchAlwaysTransactionAttributeSource source = new MatchAlwaysTransactionAttributeSource();
    source.setTransactionAttribute(new DefaultTransactionAttribute());
    TransactionInterceptor interceptor = new TransactionInterceptor(transactionManager, source);

    PollerMetadata metadata = new PollerMetadata();
    metadata.setTrigger(trigger);
    metadata.setTransactionSynchronizationFactory(synchronizationFactory());
    metadata.setAdviceChain(Collections.singletonList(interceptor));
    return metadata;
}

@Bean
@InboundChannelAdapter(channel = "ftpChannel", poller = @Poller("pollerMetadata"))
public MessageSource<InputStream> ftpMessageSource(){
    FtpStreamingMessageSource source = new FtpStreamingMessageSource(new FtpRemoteFileTemplate(ftpSessionFactory()));
    source.setRemoteDirectory("ftp/folder");
    source.setFilter(new CompositeFileListFilter<>(Arrays.asList(
            new FtpRegexPatternFileListFilter(FILE_PATTERN),
            acceptOnceFileListFilter()
    )));
    return source;
}

@Bean
public FtpPersistentAcceptOnceFileListFilter acceptOnceFileListFilter(){
    FtpPersistentAcceptOnceFileListFilter filter = new FtpPersistentAcceptOnceFileListFilter(metadataStore(), "remote");
    filter.setFlushOnUpdate(true);
    return filter;
}

@Bean
@ServiceActivator(inputChannel = "newChannel")
public MessageHandler handler(){
    return new MessageHandler(){
        @Override
        public void handleMessage(Message<?> message) throws MessagingException {
            System.out.println(message.getPayload());
            throw new MessagingException("error");
        }
    };
}

@Bean
public MessageChannel ftpChannel(){
    return new DirectChannel();
}

@Bean
public MessageChannel newChannel(){
    return new DirectChannel();
}

@Bean
public MessageChannel strChannel(){
    return new DirectChannel();
}

@Bean
@Transformer(inputChannel = "ftpChannel", outputChannel = "strChannel")
public org.springframework.integration.transformer.Transformer transformer2(){
    return new StreamTransformer("UTF-8");
}

@Bean
@Transformer(inputChannel = "strChannel", outputChannel = "newChannel")
public UnmarshallingTransformer transformer(){
    UnmarshallingTransformer transformer = new UnmarshallingTransformer(unmarshaller());
    return transformer;
}

@Bean
public Jaxb2Marshaller unmarshaller(){
    Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
    unmarshaller.setContextPath("com.generated.xsd");
    return unmarshaller;
}

我的问题是在throw new MessagingException("error");上,所有ftp文件都保存到ftpStore.properties并在下次重新加载时(例如,如果JVM失败),这些文件将不再被处理。如何确保事务处于适当位置(即如果没有异常文件保存到ftpStore.properties,否则不会)?是否有一些教程要遵循以便从FTP服务器下载文件的故障?

1 个答案:

答案 0 :(得分:1)

对此问题有一个ResettableFileListFilter抽象。

事实上你的FtpPersistentAcceptOnceFileListFilter就是这样的一个:

  

如果在同步文件后,下游流处理文件时发生错误,则不会自动回滚过滤器,因此默认情况下不会重新处理失败的文件。

     

如果您希望在发生故障后重新处理此类文件,可以使用类似于以下内容的配置,以便于从过滤器中删除失败的文件。这适用于任何ResettableFileListFilter

XML配置示例如下:

<int:transaction-synchronization-factory id="syncFactory">
    <int:after-rollback expression="@acceptOnceFilter.remove(payload)" />
</int:transaction-synchronization-factory>

因此,您需要的是分别使用适当的synchronizationFactoryDefaultTransactionSynchronizationFactory调整ExpressionEvaluatingTransactionSynchronizationProcessor

请参阅Recovering from Failures