Azure Service Bus会话订阅调用completeAsync抛出UnsupportedOperationException异常
解决Azure Service Bus会话订阅中调用
completeAsync抛出UnsupportedOperationException的问题 我之前也碰到过一模一样的问题!核心原因很明确:会话感知的订阅里,消息的锁定是和所属会话绑定的,不能直接通过全局的SubscriptionClient来完成消息操作,必须借助会话对应的客户端上下文来处理。
问题根源
当你使用会话感知订阅时,每条消息的锁定权限是依附于它所在的会话的,并非独立存在。直接调用subscriptionClient.completeAsync(message.getLockToken())会绕过会话的锁定管理逻辑,所以SDK会抛出UnsupportedOperationException来阻止这种非法操作。
解决方案(分SDK版本)
1. 旧版SDK(com.microsoft.azure:azure-servicebus)
你需要替换掉普通的MessageHandler,改用SessionHandler来处理会话消息,并且通过SessionClient完成消息操作,而非全局的SubscriptionClient:
// 初始化订阅客户端 SubscriptionClient subscriptionClient = new SubscriptionClient( "你的Service Bus连接字符串", "aaaa", "zzzsubscription", ReceiveMode.PEEKLOCK ); // 注册会话专属处理器 subscriptionClient.registerSessionHandler( new SessionHandler() { @Override public CompletableFuture<Void> onMessageAsync(SessionClient sessionClient, Message message) { // 这里写你的消息业务处理逻辑 System.out.println("收到会话消息:" + new String(message.getBody())); // 关键操作:通过当前会话的client完成消息,而非全局的subscriptionClient return sessionClient.completeAsync(message.getLockToken()); } @Override public void notifyException(Throwable exception, ExceptionPhase phase) { System.err.println("会话处理出错:" + exception.getMessage()); } }, new SessionHandlerOptions() );
2. 新版SDK(com.azure:azure-messaging-servicebus)
如果用的是最新版Service Bus SDK,推荐使用ServiceBusSessionProcessorClient来处理会话消息,API设计更简洁直观:
ServiceBusSessionProcessorClient sessionProcessor = new ServiceBusSessionProcessorClientBuilder() .connectionString("你的Service Bus连接字符串") .topicName("aaaa") .subscriptionName("zzzsubscription") // 处理会话内的消息 .processMessage(context -> { ServiceBusReceivedMessage message = context.getMessage(); System.out.println("收到会话消息:" + new String(message.getBody())); // 通过上下文完成消息,自动关联当前会话 return context.complete(); }) // 处理错误场景 .processError(context -> { System.err.println("会话处理出错:" + context.getThrowable().getMessage()); return Mono.empty(); }) .buildProcessorClient(); // 启动会话处理器 sessionProcessor.start();
关键注意事项
- 会话感知订阅必须使用会话专属的处理器(
SessionHandler/ServiceBusSessionProcessorClient),不能用普通的消息处理器 - 消息的完成、放弃、延期等操作,必须通过当前会话的客户端/上下文执行,绝对不能直接用全局的订阅客户端
内容的提问来源于stack exchange,提问作者Ashok Goli
相关产品推荐
相关产品推荐

