I am trying to solve this issue on which I don't understand fully why is not working.
I have 2 topics. TOPIC_A
on which I can send my messages and I receive them correctly. And once the message has been received, I would like to send it to another topic, TOPIC_B
. So far I have been testing this code locally and everything worked just fine. But since when I started using an azure.function servicebus. The code start acting funny. And here is my code:
import logging
import azure.functions as func
import json
import boto3
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
from azure.servicebus import ServiceBusClient, ServiceBusMessage
def main(message: func.ServiceBusMessage):
logging.info(message)
print(message)
#KeyVault Configuration
KeyVault_Url = f'url'
credential = DefaultAzureCredential()
client_keyvault = SecretClient(vault_url=KeyVault_Url, credential=credential)
# # Service Bus Connection string
CONNECTION_STR = client_keyvault.get_secret("CONN").value
# For receiving the feedback from campaigns
TOPIC_NAME_A = "TOPICA"
SUBSCRIPTION_NAME = "XXX"
# For sending feedback and results of sentiment analysis and language detection
TOPIC_NAME_B = "TOPICB"
comprehend = boto3.client(service_name='comprehend', region_name='eu-west-1', aws_access_key_id=client_keyvault.get_secret("ID").value, aws_secret_access_key=client_keyvault.get_secret("SECRET").value)
# This block will receiver the messages from the service bus listed above.
# Please mind, once the message get received and printed (json format) that event will be destroyed from the portal service bus.
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR)
with servicebus_client:
receiver = servicebus_client.get_subscription_receiver(
topic_name=TOPIC_NAME_A,
subscription_name=SUBSCRIPTION_NAME
)
with receiver:
received_msgs = receiver.receive_messages(max_message_count=10, max_wait_time=60)
output_global = {}
for msg in received_msgs:
message1 = str(msg)
res = json.loads(message1)
# extracting the text from the message from service bus
text = res['Text']
#passing the text to comprehend
result_json= json.dumps(comprehend.detect_sentiment(Text=text, LanguageCode='en'), sort_keys=True, indent=4)
result = json.loads(result_json) # converting json to python dictionary
print(result)
# logging.info("Result from comprehend" , result)
#extracting the sentiment value
sentiment = result["Sentiment"]
#extracting the sentiment score
if sentiment == "POSITIVE":
value = round(result["SentimentScore"]["Positive"] * 100,2)
elif sentiment == "NEGATIVE":
value = round(result["SentimentScore"]["Negative"] * 100,2)
elif sentiment == "NEUTRAL":
value = round(result["SentimentScore"]["Neutral"] * 100,2)
elif sentiment == "MIXED":
value = round(result["SentimentScore"]["Mixed"] * 100,2)
# To detect the language of the feedback, the text received from service bus is passed to the function below
lang_result=json.dumps(comprehend.detect_dominant_language(Text = text), sort_keys=True, indent=4)
#converting languages detection results into a dictionary
lang_result_json=json.loads(lang_result)
#Formatting the score from the results
for line in lang_result_json["Languages"]:
line['Score'] = round(line['Score']* 100, 2)
#storing the output of sentiment analysis, language detection and ids in a dictionary and converting it to JSON
output = {
'XXX': res['XXX'],
'XXX Id': res['XXX'],
'XXX': res['XXX'],
'XXX': res['XXX'],
'XXX': res['XXX'],
'Sentiment': sentiment,
'Value': value,
'Languages': lang_result_json['Languages']
}
# logging.info("Message Body: " + output)
output_json = json.dumps(output, ensure_ascii=False)
#-------------------------------------------------------------------------------------------------------
# Sending the processed output (output_json) in json format to another service bus
def send_output(sender):
message2 = ServiceBusMessage(
output_json,
content_type="XXX", #setting the content type so that the service bus can route it.
ApplicationProperties={b'tenantcode':msg.ApplicationProperties[b'tenantcode']} #setting the tenant code
)
sender.send_messages(message2)
servicebus_client = servicebus_client.from_connection_string(conn_str=CONNECTION_STR, logging_enable=True)
with servicebus_client:
sender = servicebus_client.get_topic_sender(topic_name=TOPIC_NAME_B)
with sender:
send_output(sender)
this is my host.json
{
"version": "2.0",
"extensions": {
"serviceBus": {
"messageHandlerOptions": {
"autoComplete": true
}
}
},
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[2.*, 3.0.0)"
}
}
and this is my function.json
{
"scriptFile": "outthinkServiceBus.py",
"entryPoint": "main",
"bindings": [
{
"name": "message",
"type": "serviceBusTrigger",
"direction": "in",
"topicName": "XXX",
"subscriptionName": "XXX",
"connection": "XXX"
}
]
}
Inside the received I have a for loop msg
on which I would like to loop over all the messages inside the topic, and one by one send them to the topicB.
Everything works fine as it is, and in the output of azure function, I can see this message
2021-10-15 15:23:45.124
Message receiver b'receiver-link-' state changed from <MessageReceiverState.Open: 3> to <MessageReceiverState.Closing: 4> on connection: b'SBReceiver-'
Information
2021-10-15 15:23:45.552
Shutting down connection b'SBReceiver-'.
So the processing gets until the receiver, but the function sender, never get triggered.
If I remove the for loop, the code works just fine. I am able to see the sender triggering and completing successfully.
Any help to understand where is the mistake and what I am doing wrong?
Thank you so much for any help you can provide me with. Andplease if you need more info just ask
UPDATE:
I have tried to indent the send_out function outside the for
loop, in this case the function sent_out
triggers but the azure function Servicebus fails as the output_json
is out of scope. So far the only thing I could figure out is that for some reason, the function defined in the loop, never fires.