我有一个简单的IntegrationFlow
,我正试图通过事务管理来保护它。从较高级别开始,它会轮询目录中的文件,将该文件gzips到磁盘上的新位置,然后将该第二个文件上载到S3。如果它提交,我想将两个路径发布到一个通道(它们将被删除);如果它回滚,我想将它们发布到不同的渠道(它们将被存档)。
我的(缩写)尝试配置如下所示:
@Bean
public IntegrationFlow fromFileFlow(@Qualifier("inboundMessageDirectory") Path inboundMessageDirectory,
@Qualifier("consumableFileFilter") FileListFilter<File> fileListFilter,
@Qualifier(ChannelNames.TO_GZIP_SERVICE) MessageChannel outbound,
@Qualifier("transactionSynchronizationFactory") TransactionSynchronizationFactory transactionSynchronizationFactory) {
return IntegrationFlows
.from(s -> s.file(inboundMessageDirectory.toFile()),
e -> e.poller(Pollers
.fixedDelay(100)
.transactionSynchronizationFactory(transactionSynchronizationFactory)
.transactional(new PseudoTransactionManager())
.get()))
.channel(outbound)
.get();
}
服务如下:
@ServiceActivator(inputChannel = ChannelNames.TO_GZIP_SERVICE, outputChannel = ChannelNames.TO_S3_SERVICE)
public Path gzip(@Payload Path path, @Header(ApplicationHeaders.REFERENCE_ID) String referenceId, @Header(ApplicationHeaders.DATA_TYPE) String dataType,
@Header(ApplicationHeaders.BUCKET_END) long bucketEnd) throws IOException {
// ...
}
@ServiceActivator(inputChannel = ChannelNames.TO_S3_SERVICE)
@Retryable(interceptor = RETRY_INTERCEPTOR_BEAN_NAME)
public void sendToS3(@Payload Path path, @Header(ApplicationHeaders.BUCKET_END) long bucketStart,
@Header(ApplicationHeaders.DATA_TYPE) String dataType) throws IOException {
// ...
}
我的自定义TransactionSynchronizationProcessor
(我使用DefaultTransactionSynchronizationFactory
)或多或少地实现如下(代码未显示从消息有效负载中提取路径并将其存储在IntegrationResourceHolder的属性中):
@Override
public void processBeforeCommit(IntegrationResourceHolder holder) {
updatePaths(holder);
}
@Override
public void processAfterCommit(IntegrationResourceHolder holder) {
updateAndSend(successChannel, holder);
}
@Override
public void processAfterRollback(IntegrationResourceHolder holder) {
updateAndSend(failureChannel, holder);
}
我的理解是,因为所有插页式频道都是直接频道,所以交易也应包含服务。因为它在之前,提交之后和回滚之后更新,我希望它在开始时访问消息,获取解压缩路径,然后在最后访问它并获取gzip压缩路径 - 然后尝试操作他们。但是,只提取未经过拉链的路径。
显然,我对交易的申请(和理解)缺少了一些东西。我实施所需行为的正确方法是什么?
答案 0 :(得分:1)
对于transactional
和transactionSynchronizationFactory
,我们只担心source
。作为数据的最终结果对于事务资源并不重要。我们需要知道只有提交或rallback交易的状态。
这就是为什么IntegrationResourceHolder
具有message
属性来携带源数据以在TX结束时担心的原因。
就像尝试在TX结束时仅在数据库事务和数据中成像一样。对,没有那个数据!只有TX的输入很重要。
但是,您可以使用额外的ResourceHolder
和ResourceHolderSynchronization
来实现您的要求,以便在S3商店之前使用。简单ThreadLocal
也可能有所帮助。但一定要在TX结束时正确清除它。
从另一方面考虑使用headers
的{{1}}消息来携带您需要的所有内容。为此,s.file
从Spring Integration 4.2开始就很有用。