Azure 如何在使用AMQP建立到事件中心的连接时设置x-opt-offset以避免消息重播
我的应用程序连接到azure事件中心以接收和处理消息。我发现每次重新启动应用程序时,保留期内的所有消息都会被重放。我阅读了有关偏移量的文章以避免此问题,我有一个方法将与azure事件中心的连接设置为:Azure 如何在使用AMQP建立到事件中心的连接时设置x-opt-offset以避免消息重播,azure,amqp,azure-eventhub,Azure,Amqp,Azure Eventhub,我的应用程序连接到azure事件中心以接收和处理消息。我发现每次重新启动应用程序时,保留期内的所有消息都会被重放。我阅读了有关偏移量的文章以避免此问题,我有一个方法将与azure事件中心的连接设置为: MessageConsumer connect(){ //设置JNDI上下文 BatchEventHubConfig BatchEventHubConfig=//包含配置的映射 字符串queueName=“EventHub” 字符串connectionFactoryName=“SBCF” //长偏
MessageConsumer connect(){
//设置JNDI上下文
BatchEventHubConfig BatchEventHubConfig=//包含配置的映射
字符串queueName=“EventHub”
字符串connectionFactoryName=“SBCF”
//长偏移量=batchAccountManager.batchStorageManager.batchJobMsgCheckpointService.get(batchEventHubConfig.namespace,batchEventHubConfig.getMessageQueueAddress(partitionInx,true))?.offset
Hashtable Hashtable=新的Hashtable()
put(“connectionfactory.${connectionFactoryName}”,batchEventHubConfig.getAMQPConnectionURI())
hashtable.put(“queue.${queueName}”,batchEventHubConfig.getMessageQueueAddress(partitionInx))
//put(“apache.org:selector-filter:string”,“amqp.annotation.x-opt-offset>'${offset}'”)
put(Context.INITIAL\u Context\u工厂,“org.apache.qpid.amqp\u 1\u 0.jms.jndi.PropertiesFileInitialContextFactory”)
上下文上下文=新的初始上下文(哈希表)
ConnectionFactory工厂=(ConnectionFactory)上下文。查找(connectionFactoryName)
队列=(目标)上下文。查找(队列名称)
connection=factory.createConnection(batchEventHubConfig.sasPolicyName,batchEventHubConfig.sasPolicyKey)
connection.setExceptionListener(新的BatchExceptionListener(eventHubConnection:this))
connection.start()
session=connection.createSession(false,session.CLIENT\u确认)
messageConsumer=session.createConsumer(队列)
messageConsumer.setMessageListener(messageListener)
消息消费者
}
注释掉的偏移量代码是我在阅读这里之后尝试的:
设置偏移量的正确方法是什么,以便在应用程序重新启动时不会重新播放消息?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分支并应用此修补程序,要么将修改后的类放在类路径中以覆盖原始的(非常糟糕的解决方案)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);
而且它有效
因此,要么你使用ApacheQPID的分支并应用此补丁,要么你将修改后的类放在类路径中以覆盖原始的(非常糟糕的解决方案)这比我想象的要容易得多!找到此链接: 所以我所要做的就是像这样添加过滤条件:
messageConsumer = session.createConsumer(queue, "amqp.annotation.x-opt-offset >= '${messageOffset}'")
这比我想象的要容易得多!找到此链接: 所以我所要做的就是像这样添加过滤条件:
messageConsumer = session.createConsumer(queue, "amqp.annotation.x-opt-offset >= '${messageOffset}'")
受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 consumer = session.createConsumer(queue, String.format("x-opt-offset > %s", offset));
现在,可以在创建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 consumer = session.createConsumer(queue, String.format("x-opt-offset > %s", offset));
或
请参阅以获取工作分叉。受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 consumer = session.createConsumer(queue, String.format("x-opt-offset > %s", offset));
现在,可以在创建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 consumer = session.createConsumer(queue, String.format("x-opt-offset > %s", offset));
或
请参阅以获取工作分叉。这对我不起作用,将导致如下异常:javax.jms.InvalidSelectorException:amqp.annotation.x-opt-offset>='1'它必须是有效的偏移量值,如果以空队列开始,则该值应为-1。使用qpid jms客户端时,名称中带有点的过滤器,将导致无效的SelectorException。关于空队列,你是对的。我也遇到了。但这将导致另一个错误。使用我显示为答案的分叉版本,可以与qpid jms客户端配合使用这对我不起作用,并将导致如下异常:javax.jms.InvalidSelectorException:amqp.annotation.x-opt-offset>='1'它必须是有效的偏移量值,如果以空队列开始,则该值应为-1。使用qpid jms客户端时,名称中带有点的筛选器将导致InvalidSelectorException。关于空队列,你是对的。我也遇到了。但这将导致另一个错误。使用我作为答案展示的分叉版本,可以很好地与qpid jms客户机配合使用