Reputation: 1569
I have an azure function ServiceBus on which I would like to customise its properties.
I have 2 topics, I send a message on topic 1(on which I do some processing) and send its output to the second topic. Due to the fact that this messages comes from different resources, I would like to have application properties that makes clear from where this message is coming.
so I have my code as follow:
def main(message: func.ServiceBusMessage):
logging.info(message)
print(message)
message_content_type = message.content_type
message_body = message.get_body().decode("utf-8")
.....
.....
message1 = str(message_body)
def send_output(sender):
message_out = ServiceBusMessage(
output_json,
content_type="ModuleCommentAnalyzed", #setting the content type so that the service bus can route it.
application_properties={b'source':message.application_properties[b'source']} #setting the tenant code
)
sender.send_messages(message_out)
But when i send a message, the function fails throwing the following error.
Result: Failure Exception: AttributeError: 'ServiceBusMessage' object has no attribute 'application_properties' Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 402, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.9/concurrent/futures/thread.py", line 52, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 606, in _run_sync_func return ExtensionManager.get_sync_invocation_wrapper(context, File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper result = function(**args) File "/home/site/wwwroot/function/testServiceBus.py", line 118, in main send_output(sender) File "/home/site/wwwroot/function/testServiceBus.py", line 108, in send_output application_properties={b'source':message.application_properties[b'source']} #setting the tenant code
I tried to replace message
with variable message1
but in this case I get an error str does not contain an attribute...
Any help will be much appreciated to understand what I am doing wrong and better understand how this works.
Thank you so much in advance and please if you need more info just let me know
UPDATE.
According to Microsoft documentation, from servicebus 5.x
they replace user_propertieswith
applicationProperties`
I did tried both of them but nothing work.
Here is to make the OP a bit clear.
This is my updated code
import logging
import json
import azure.functions as func
from azure.servicebus import ServiceBusClient, ServiceBusMessage
def main(message: func.ServiceBusMessage):
# Log the Service Bus Message as plaintext
message_content_type = message.content_type
message_body = message.get_body().decode("utf-8")
result = json.dumps({
'message_id': message.message_id,
'body': message.get_body().decode('utf-8'),
'content_type': message.content_type,
'user_properties': message.user_properties,
'metadata' : message.metadata
})
logging.info(result)
# logging.info("Python ServiceBus topic trigger processed message.")
# logging.info("Message Content Type: " + message_content_type)
# logging.info("Message Body: " + message_body)
CONN_STR = "XXX"
topic_b = "topic_b"
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONN_STR)
def send_output(sender):
message_out = ServiceBusMessage(
result,
content_type="application/json", #setting the content type so that the service bus can route it.
user_properties={b'tenant': result.user_properties[b'MessageId']} #setting the tenant code
)
sender.send_messages(message_out)
servicebus_client_out = servicebus_client.from_connection_string(conn_str=CONN_STR, logging_enable=True)
with servicebus_client:
sender = servicebus_client_out.get_topic_sender(topic_name=topic_b)
with sender:
send_output(sender)
For testing purpose, I am trying to add a custom property on with to return the message_id
as it is part of the message coming in. But I get this error
Result: Failure Exception: AttributeError: 'str' object has no attribute 'user_properties' Stack
So I tried with sender
and the message was
Result: Failure Exception: AttributeError: 'ServiceBus' object has no attribute 'user_properties' Stack
This is something that I really cannot find anywhere in Microsoft documentation.
So to make sure that everything was just fine I tried with the following code
application_properties={'tenant': 'DEMO'}
And this worked just fine.
Please if anyone have any hint on this issue I would be grateful
Upvotes: 1
Views: 1902
Reputation: 1569
@gvee Yes the documentation is totally contradictory and the library is not fully clear. I managed to solve the issue I and I hope this will help anyone in the future.
This issue has been solved for the library service-bus 7+
In my specific case I needed the function 2 perform 2 important steps. And they are as follow
before
to send it out.Now the main issue for me, as mentioned in my OP..was that the library was not able to recognise the attribute I was declaring. This was mainly due to the library having 2 attributes, user_properties AND
application_properties.
So what I had to do in my code is as follow.
On the servicebus message
I had to use user_properties
to retrieve a specific property.
def main(message: func.ServiceBusMessage):
logging.info(message)
test_user = message.user_properties['property']
Doing this I was able to extract the string I was looking for. so far so good.
Then I wanted to attach that test_user
as a property to the message while sending it out to the topic B.. so I tried to use once again user_properties
but this failed as the attribute was not recognised.
And here the weird think. I used application_properties
at it worked, as follow
def send_output(sender):
message_out = ServiceBusMessage(
output_json,
content_type="ModuleCommentAnalyzed", #setting the content type so that the service bus can route it.
application_properties={'property': test_user}
)
sender.send_messages(message_out)
So my conclusion was that to retrieve the property, I should use user_properties
and to set a custom property I have to use application_properties
.
I can't give a detailed explanation why it does work in this way, as documentation is not clear at all (at least for me) and the source code is not aligned correctly with the library functionality.
But I hope this will help somebody in the future.
Upvotes: 1
Reputation: 17161
I have to agree that the documentation is contradictory.
So, let's ignore the docs 😅 and go straight to the source: https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/servicebus/azure-servicebus/azure/servicebus/_common/message.py#L63
This tells us that the correct keyword argument is application_properties
.
Reminder: this answer is pointing out the current (at the time of writing) code in the main
branch. This appears to be for version 7+ of the azure-servicebus
package.
Upvotes: 1