You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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类型的对象,而非原始元组。

修改步骤:

  1. 导入AzureNamedKeyCredential类
  2. 将元组形式的凭证替换为AzureNamedKeyCredential实例
  3. 补充死信队列读取参数、修正消息读取/处理逻辑(适配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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:13:13