当rabbitmq停止运行时停止轮询文件:spring集成

时间:2018-06-19 17:25:47

标签: rabbitmq spring-integration spring-amqp spring-integration-sftp

我正在一个项目中,在该项目中,我们从sftp服务器轮询文件,并将其流式传输到Rabbitmq队列中的对象中。现在,当rabbitmq关闭时,它仍会轮询并从服务器删除文件,并且当rabbitmq处于关闭状态时将其发送到队列时会丢失该文件。我正在使用 ExpressionEvaluatingRequestHandlerAdvice 在成功转换后删除文件。我的代码如下:

@Bean
public SessionFactory<ChannelSftp.LsEntry> sftpSessionFactory() {
    DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
    factory.setHost(sftpProperties.getSftpHost());
    factory.setPort(sftpProperties.getSftpPort());
    factory.setUser(sftpProperties.getSftpPathUser());
    factory.setPassword(sftpProperties.getSftpPathPassword());
    factory.setAllowUnknownKeys(true);
    return new CachingSessionFactory<>(factory);
}    

@Bean
public SftpRemoteFileTemplate sftpRemoteFileTemplate() {
    return new SftpRemoteFileTemplate(sftpSessionFactory());
}

@Bean
@InboundChannelAdapter(channel = TransformerChannel.TRANSFORMER_OUTPUT, autoStartup = "false",
        poller = @Poller(value = "customPoller"))
public MessageSource<InputStream> sftpMessageSource() {
    SftpStreamingMessageSource messageSource = new SftpStreamingMessageSource(sftpRemoteFileTemplate,
            null);
    messageSource.setRemoteDirectory(sftpProperties.getSftpDirPath());
    messageSource.setFilter(new SftpPersistentAcceptOnceFileListFilter(new SimpleMetadataStore(),
            "streaming"));
    messageSource.setFilter(new SftpSimplePatternFileListFilter("*.txt"));
    return messageSource;
}    


@Bean
@Transformer(inputChannel = TransformerChannel.TRANSFORMER_OUTPUT,
        outputChannel = SFTPOutputChannel.SFTP_OUTPUT,
        adviceChain = "deleteAdvice")
public org.springframework.integration.transformer.Transformer transformer() {
    return new SFTPTransformerService("UTF-8");
}

@Bean
public ExpressionEvaluatingRequestHandlerAdvice deleteAdvice() {
    ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
        advice.setOnSuccessExpressionString(
                "@sftpRemoteFileTemplate.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])");
    advice.setPropagateEvaluationFailures(false);
    return advice;
}

我不希望在Rabbitmq服务器关闭时从远程sftp服务器上删除/轮询文件。我怎样才能做到这一点?

更新

抱歉,我没有使用春季云流兔活页夹。这是变压器服务:

public class SFTPTransformerService extends StreamTransformer {
public SFTPTransformerService(String charset) {
    super(charset);
}

@Override
protected Object doTransform(Message<?> message) throws Exception {
    String fileName = message.getHeaders().get("file_remoteFile", String.class);
    Object fileContents = super.doTransform(message);
    return new customFileDTO(fileName, (String) fileContents);
}
}

UPDATE-2 根据建议,我在customPoller上添加了TransactionSynchronizationFactory。现在,当兔子服务器关闭时,它不会轮询文件,但是当服务器启动时,它会不断地反复轮询同一文件!我不知道为什么?我想我无法在PollerSpec上使用4.3.2版本的即时消息。

@Bean(name = "customPoller")
public PollerMetadata pollerMetadataDTX(StartStopTrigger startStopTrigger,
                                        CustomTriggerAdvice customTriggerAdvice) {
    PollerMetadata pollerMetadata = new PollerMetadata();
    pollerMetadata.setAdviceChain(Collections.singletonList(customTriggerAdvice));
    pollerMetadata.setTrigger(startStopTrigger);
    pollerMetadata.setMaxMessagesPerPoll(Long.valueOf(sftpProperties.getMaxMessagePoll()));
    ExpressionEvaluatingTransactionSynchronizationProcessor syncProcessor =
            new ExpressionEvaluatingTransactionSynchronizationProcessor();
    syncProcessor.setBeanFactory(applicationContext.getAutowireCapableBeanFactory());
    syncProcessor.setBeforeCommitChannel(
            applicationContext.getBean(TransformerChannel.TRANSFORMER_OUTPUT, MessageChannel.class));
    syncProcessor
            .setAfterCommitChannel(
                    applicationContext.getBean(SFTPOutputChannel.SFTP_OUTPUT, MessageChannel.class));
    syncProcessor.setAfterCommitExpression(new SpelExpressionParser().parseExpression(
            "@sftpRemoteFileTemplate.remove(headers['file_remoteDirectory'] + headers['file_remoteFile'])"));
    DefaultTransactionSynchronizationFactory defaultTransactionSynchronizationFactory =
            new DefaultTransactionSynchronizationFactory(syncProcessor);
    pollerMetadata.setTransactionSynchronizationFactory(defaultTransactionSynchronizationFactory);
    return pollerMetadata;
}

我不知道您是否需要此信息,但是我的CustomTriggerAdviceStartStopTrigger看起来像这样:

@Component
public class CustomTriggerAdvice extends AbstractMessageSourceAdvice {

@Autowired private StartStopTrigger startStopTrigger;

@Override
public boolean beforeReceive(MessageSource<?> source) {
    return true;
}

@Override
public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
    if (result == null) {
        if (startStopTrigger.getStart()) {
            startStopTrigger.stop();
        }
    } else {
        if (!startStopTrigger.getStart()) {
            startStopTrigger.stop();
        }
    }
    return result;
}

}


public class StartStopTrigger implements Trigger {

private PeriodicTrigger startTrigger;
private boolean start;

public StartStopTrigger(PeriodicTrigger startTrigger, boolean start) {
    this.startTrigger = startTrigger;
    this.start = start;
}

@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
    if (!start) {
        return null;
    }
    start = true;
    return startTrigger.nextExecutionTime(triggerContext);
}

public void stop() {
    start = false;
}

public void start() {
    start = true;
}

public boolean getStart() {
    return this.start;
}
}

1 个答案:

答案 0 :(得分:0)

好吧,很高兴能看到您的SFTPTransformerService并确定在出现经纪人异常的情况下如何执行onSuccessExpression

您还不仅应该引发异常而不执行删除,还应该考虑添加RequestHandlerRetryAdvice以将文件重新发送到RabbitMQ:https://docs.spring.io/spring-integration/docs/5.0.6.RELEASE/reference/html/messaging-endpoints-chapter.html#retry-advice

更新

因此,好吧,由于Gary猜想您是在内部流程之后使用Spring Cloud Stream将消息发送到Rabbit Binder的(非常可悲的是,您最初并未共享该信息),因此您需要查看Binder错误处理:https://docs.spring.io/spring-cloud-stream/docs/Elmhurst.RELEASE/reference/htmlsingle/#_retry_with_the_rabbitmq_binder

这是正确的,ExpressionEvaluatingRequestHandlerAdvice仅适用于SFTPTransformerService,仅此而已。下游错误(在活页夹中)尚未包括在此过程中。

更新2

是的...我认为Gary是对的,除非我们在TransactionSynchronizationFactory级别上配置customPoller而不是ExpressionEvaluatingRequestHandlerAdvice级别的Expression {EvaluatingRequestHandlerAdvice},否则我们别无选择。

可以使用DefaultTransactionSynchronizationFactory配置ExpressionEvaluatingTransactionSynchronizationProcessor,其目的与上述ExpressionEvaluatingRequestHandlerAdvice相似,但是在事务级别上,它将包括从SFTP Channel Adapter和以发送到AMQP尝试结束于Rabbit Binder级别。

有关更多信息,请参见参考手册:https://docs.spring.io/spring-integration/reference/html/transactions.html#transaction-synchronization

具有ExpressionEvaluatingRequestHandlerAdvice(和任何AbstractRequestHandlerAdvice)的点,它们仅在handleRequestMessage()方法周围具有边界,因此仅在组成部分期间被声明。

相关问题