【发布时间】:2018-06-19 17:25:47
【问题描述】:
我正在做一个项目,我们正在从 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 服务器中删除/轮询。我怎样才能做到这一点?
更新
抱歉,我没有提到我正在使用 Spring Cloud Stream 兔子活页夹。这是变压器服务:
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。现在当rabbit服务器关闭时它不会轮询文件,但是当服务器启动时,它会一遍又一遍地轮询同一个文件!我想不通为什么?我想我不能使用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;
}
我不知道您是否需要此信息,但我的 CustomTriggerAdvice 和 StartStopTrigger 看起来像这样:
@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;
}
}
【问题讨论】:
-
看起来你没有
start()你的startStopTriggerif (!startStopTrigger.getStart()) {。你还是打电话给stop() -
我不相信你的处理器需要
beforeCommitChannel和afterCommitChannel。关键是只有在成功发送到 AMQP 后才能删除文件。此 TX 建议确实完全适用于您的整个流程,从@InboundChannelAdapter开始,到AmqpOutboundEndpoint结束 -
@ArtemBilan 我确实通过休息电话启动了
startStopTrigger。这是它的样子:rtemBilan -
private void setSourcePollingChannelAdapter() { sourcePollingChannelAdapter.stop(); applicationContext.getBean("startStopTrigger", StartStopTrigger.class).start(); sourcePollingChannelAdapter.start(); } -
好吧,您已经更改了配置中的其他内容。
SftpPersistentAcceptOnceFileListFilter的诀窍不会再次轮询同一个文件...
标签: rabbitmq spring-integration spring-amqp spring-integration-sftp