我的应用程序连接到Azure事件中心以接收消息并进行处理。我看到每次重新启动应用程序时,保留期内的所有消息都会被重播。我读过有关偏移的内容,以避免出现此问题,并且我有一种方法将与Azure事件中心的连接设置为:
MessageConsumer connect() {
// set up JNDI context
BatchEventHubConfig batchEventHubConfig = //MAP CONTAINING CONFIG
String queueName = "EventHub"
String connectionFactoryName = "SBCF"
//Long offset = batchAccountManager.batchStorageManager.batchJobMsgCheckpointService.get(batchEventHubConfig.namespace, batchEventHubConfig.getMessageQueueAddress(partitionInx, true))?.offset
Hashtable<String, String> hashtable = new Hashtable<>()
hashtable.put("connectionfactory.${connectionFactoryName}", batchEventHubConfig.getAMQPConnectionURI())
hashtable.put("queue.${queueName}", batchEventHubConfig.getMessageQueueAddress(partitionInx))
//hashtable.put("apache.org:selector-filter:string", "amqp.annotation.x-opt-offset > '${offset}'")
hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory")
Context context = new InitialContext(hashtable)
ConnectionFactory factory = (ConnectionFactory) context.lookup(connectionFactoryName)
queue = (Destination) context.lookup(queueName)
connection = factory.createConnection(batchEventHubConfig.sasPolicyName, batchEventHubConfig.sasPolicyKey)
connection.setExceptionListener(new BatchExceptionListener(eventHubConnection: this))
connection.start()
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE)
messageConsumer = session.createConsumer(queue)
messageConsumer.setMessageListener(messageListener)
messageConsumer
}
注释掉的偏移量代码是我在这里阅读以下内容后尝试的内容:https://azure.github.io/amqpnetlite/articles/azure_eventhubs.html
设置偏移量以便在应用程序重新启动时不重播消息的正确方法是什么?
答案 0 :(得分:1)
Apche QPID不支持AMQP过滤器(基础Apache Proton J则支持)。
我通过在末尾添加以下几行来修补AmqpConsumerBuilder.configureSource()方法:
Symbol filterKey = Symbol.valueOf("apache.org:selector-filter:string");
UnknownDescribedType filterValue = new UnknownDescribedType(filterKey, String.format("%s > '%s'",amqp.annotation.x-opt-offset", lastOffset));
filters.put(filterKey, filterValue);
它有效!
因此,您可以派生Apache QPID并应用此补丁,或者将修改后的类放在类路径中以覆盖原始的(非常糟糕的解决方案)
答案 1 :(得分:0)
这比我想象的要容易得多!找到此链接:https://timjansen.github.io/jarfiller/guide/jms/selectors.xhtml
所以我所要做的就是添加这样的过滤条件:
messageConsumer = session.createConsumer(queue, "amqp.annotation.x-opt-offset >= '${messageOffset}'")
答案 2 :(得分:0)
受Mourad Zouabi答案的启发,我创建了qpid-jms存储库的派生,并如下更改了AmqpConsumerBuilder类,以允许将过滤器传递给MessageConsumer:
if (resourceInfo.getSelector() != null && !resourceInfo.getSelector().trim().equals("")) {
if (resourceInfo.getSelector().startsWith("x-opt-offset") || resourceInfo.getSelector().startsWith("x-opt-enqueued-time")) {
// support Azure Event HUB filters
// see: https://azure.github.io/amqpnetlite/articles/azure_eventhubs.html
Symbol filterKey = Symbol.valueOf("apache.org:selector-filter:string");
UnknownDescribedType filterValue = new UnknownDescribedType(filterKey,"amqp.annotation." + resourceInfo.getSelector().trim());
filters.put(filterKey, filterValue);
} else {
filters.put(JMS_SELECTOR_SYMBOL, new AmqpJmsSelectorType(resourceInfo.getSelector()));
}
}
if (!filters.isEmpty()) {
source.setFilter(filters);
}
现在,在创建MessageConsumer时可以通过过滤器:
MessageConsumer consumer = session.createConsumer(queue, String.format("x-opt-offset > %s", offset));
或
MessageConsumer consumer = session.createConsumer(queue, String.format("x-opt-enqueued-time > %s", timeStamp));
有关工作叉,请参见https://github.com/ekkelenkamp/qpid-jms。