Azure ServiceBusError求助:‘tuple’对象无‘get_token’属性
ServiceBus死信消息重入队报错:'tuple' object has no attribute 'get_token'
问题说明
运行死信消息重新入队的Python代码时,触发AttributeError: 'tuple' object has no attribute 'get_token'错误,后续在使用接收器上下文管理器时再次抛出相同根因的ServiceBusError。
错误信息
Exception has occurred: ServiceBusError Handler failed: 'tuple' object has no attribute 'get_token'. AttributeError: 'tuple' object has no attribute 'get_token'
在处理上述异常期间,又发生了另一个异常:
File "C:\Users\asisaacr\Downloads\project work\DeadletterRequeue\requeue.py", line 39, in <module> with from_subscription_receiver: azure.servicebus.exceptions.ServiceBusError: Handler failed: 'tuple' object has no attribute 'get_token'.
原代码
from azure.servicebus import ServiceBusClient, ServiceBusMessage import json import configparser # Read configuration from config.conf file config = configparser.ConfigParser() config.read('config.conf') service_namespace = config.get('svcbus', 'service_namespace') shared_access_key_name = config.get('svcbus', 'shared_access_key_name') shared_access_key_value = config.get('svcbus', 'shared_access_key') from_subscription_name = config.get('svcbus', 'from_subscription_name') to_topic_name = config.get('svcbus', 'to_topic_name') batch_size = int(config.get('svcbus', 'Batch')) # Create a ServiceBusClient with the shared access key credential for the source subscription bus_service_source = ServiceBusClient( fully_qualified_namespace=service_namespace, credential=(shared_access_key_name, shared_access_key_value) ) # Create a ServiceBusClient with the shared access key credential for the destination topic bus_service_destination = ServiceBusClient( fully_qualified_namespace=service_namespace, credential=(shared_access_key_name, shared_access_key_value) ) # Get a sender for the destination topic to_topic_sender = bus_service_destination.get_topic_sender(to_topic_name) # Get a receiver for the source subscription's dead letter queue from_subscription_receiver = bus_service_source.get_subscription_receiver( topic_name=to_topic_name, subscription_name=from_subscription_name ) counter = 0 with from_subscription_receiver: for message in from_subscription_receiver.peek_messages(max_message_count=batch_size): print(f"Reading dead letter from {from_subscription_name}:") request = json.loads(str(message)) props = message.user_properties if b"DeadLetterReason" in props: del props[b"DeadLetterReason"] if b"DeadLetterErrorDescription" in props: del props[b"DeadLetterErrorDescription"] msg = ServiceBusMessage(json.dumps(request)) msg.user_properties = props to_topic_sender.send_messages(msg) print(f"...message removed after being added to topic: {to_topic_name} {counter}") message.complete() counter += 1 if counter == batch_size: break # Close the ServiceBusClients bus_service_source.close() bus_service_destination.close()
解决方案
错误根源是创建ServiceBusClient时,credential参数传入了元组(shared_access_key_name, shared_access_key_value),但Azure ServiceBus SDK要求传入AzureNamedKeyCredential类型的对象,而非原始元组。
修改步骤:
- 导入
AzureNamedKeyCredential类 - 将元组形式的凭证替换为
AzureNamedKeyCredential实例 - 补充死信队列读取参数、修正消息读取/处理逻辑(适配SDK行为)
修改后的代码
from azure.servicebus import ServiceBusClient, ServiceBusMessage, AzureNamedKeyCredential # 新增导入 import json import configparser # Read configuration from config.conf file config = configparser.ConfigParser() config.read('config.conf') service_namespace = config.get('svcbus', 'service_namespace') shared_access_key_name = config.get('svcbus', 'shared_access_key_name') shared_access_key_value = config.get('svcbus', 'shared_access_key') from_subscription_name = config.get('svcbus', 'from_subscription_name') to_topic_name = config.get('svcbus', 'to_topic_name') batch_size = int(config.get('svcbus', 'Batch')) # 创建AzureNamedKeyCredential实例 credential = AzureNamedKeyCredential(shared_access_key_name, shared_access_key_value) # Create a ServiceBusClient with the shared access key credential for the source subscription bus_service_source = ServiceBusClient( fully_qualified_namespace=service_namespace, credential=credential # 使用凭证实例,而非元组 ) # Create a ServiceBusClient with the shared access key credential for the destination topic bus_service_destination = ServiceBusClient( fully_qualified_namespace=service_namespace, credential=credential # 复用同一个凭证实例 ) # Get a sender for the destination topic to_topic_sender = bus_service_destination.get_topic_sender(to_topic_name) # Get a receiver for the source subscription's dead letter queue from_subscription_receiver = bus_service_source.get_subscription_receiver( topic_name=to_topic_name, subscription_name=from_subscription_name, sub_queue="dead_letter" # 显式指定读取死信队列 ) counter = 0 with from_subscription_receiver: # 用receive_messages替代peek_messages,peek仅查看不锁定,无法执行complete操作 for message in from_subscription_receiver.receive_messages(max_message_count=batch_size): print(f"Reading dead letter from {from_subscription_name}:") request = json.loads(str(message)) props = message.user_properties # 新版本SDK中user_properties的键为字符串,而非字节 if "DeadLetterReason" in props: del props["DeadLetterReason"] if "DeadLetterErrorDescription" in props: del props["DeadLetterErrorDescription"] msg = ServiceBusMessage(json.dumps(request)) msg.user_properties = props to_topic_sender.send_messages(msg) print(f"...message removed after being added to topic: {to_topic_name} {counter}") message.complete() counter += 1 if counter == batch_size: break # Close the ServiceBusClients bus_service_source.close() bus_service_destination.close()
内容的提问来源于stack exchange,提问作者Ashwin Roy
相关产品推荐
相关产品推荐

