0

I hope somebody can help me to understand what I am doing wrong with this azure function.

My idea is structure as follow.

I have 2 topics. TOPIC_A is designed to receive a message and process it and send it to TOPIC_B which I want just to have that message until when I will decide what to do with it.

and this is the actual azure function app code.

import logging
import json
import boto3
from azure.servicebus import ServiceBusClient, ServiceBusMessage
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
import azure.functions as func

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")

    logging.info("Python ServiceBus topic trigger processed message.")
    logging.info("Message Content Type: " + message_content_type)
    logging.info("Message Body: " + message_body)

    #KeyVault Configuration
    KeyVault_Url = f'keyvailt_url'
    Keyvault_Name = 'keyvalt_name'
    credential = DefaultAzureCredential()
    client_keyvault = SecretClient(vault_url=KeyVault_Url, credential=credential)
    
    # Service Bus Connection string
    CONNECTION_STR = client_keyvault.get_secret("Service-CONN").value
    # For receiving the feedback from campaigns
    TOPIC_NAME_A = "topicAname" 
    SUBSCRIPTION_NAME = "subscriptionName"

    # For sending feedback and results of sentiment analysis and language detection
    TOPIC_NAME_B = "topicBname" 


    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)

    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=5)
            

            for msg in received_msgs:

                message= str(msg)
                res = json.loads(message) 
                text = res['Text']
                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

                #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)

                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={
                'ID':res['ID'],
                'userId':res['userId'],
                'defID':res['defID']
                }

                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):
                    message = ServiceBusMessage(
                    output_json,
                    content_type="Analysis", #setting the content type so that the service bus can route it.
                    application_properties={b'CODE':msg.application_properties[b'CODE']} #setting the tenant code
                    )
                    sender.send_messages(message)
                    

                servicebus_client = ServiceBusClient.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)

                receiver.complete_message(msg)

Before to explain the issue I have with the function, I will explain what happen if I run this code locally.

If I send a message to the TOPIC_A, and head to that topic from azure portal, I can see the message in the RECEIVED tab, once I run my python code, that message from TOPIC_A get consumed and sent to TOPIC_B, where it stays in RECEIVED. And this is exactly the output I am expecting.

Now, I moved the entire logic under an azure function, I send the message to TOPIC_A..and instantly I see the message ending under DEADLETTERS, and in my azure function I get this error.

Result: Failure Exception: ImportError: cannot import name 'c_uamqp' from partially initialized module 'uamqp' (most likely due to a circular import) (/home/site/wwwroot/.python_packages/lib/site-packages/uamqp/__init__.py). Troubleshooting Guide: https://aka.ms/functions-modulenotfound Stack

while if I peek the message (TOPIC_A) in the dead letter I see this message:

deadletterreason "MaxDeliveryCountExceeded"

As far as I understand, is that the messages end so fast under dead letter, while my code is looking for the message under RECEIVED, it tries 10 times and then fails.

But the think that I am having trouble to understand, is why this is happening only when I use the azure function.

If anyone can help me to understand the problem, I will be great full.

Please if you need anymore details, just let me know.

UPDATE:

After different debug process, I can surely say that the issue is due to the uamqp but I don't understand why is not working.

I am running my pipeline on a ubuntu worker.

my requirement.txt has:

azure-functions
azure-servicebus==7.0.0
boto3
azure-keyvault
azure-identity
uamqp

and in the pipeline output I can see that has been installed

uamqp-1.4.3

but yet I am getting the same exact error:

Result: Failure Exception: ImportError: cannot import name 'c_uamqp' from partially initialized module 'uamqp' (most likely due to a circular import) (/home/site/wwwroot/.python_packages/lib/site-packages/uamqp/__init__.py). Troubleshooting Guide: https://aka.ms/functions-modulenotfound Stack: File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/dispatcher.py", line 305, in _handle__function_load_request func = loader.load_function( File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 42, in call raise extend_exception_message(e, message) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/utils/wrappers.py", line 40, in call return func(*args, **kwargs) File "/azure-functions-host/workers/python/3.9/LINUX/X64/azure_functions_worker/loader.py", line 83, in load_function mod = importlib.import_module(fullmodname) File "/usr/local/lib/python3.9/importlib/__init__.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1030, in _gcd_import File "<frozen importlib._bootstrap>", line 1007, in _find_and_load File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 680, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 850, in exec_module File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed File "/home/site/wwwroot/myfunction/testServiceBus.py", line 4, in <module> from azure.servicebus import ServiceBusClient, ServiceBusMessage File "/home/site/wwwroot/.python_packages/lib/site-packages/azure/servicebus/__init__.py", line 6, in <module> from uamqp import constants File "/home/site/wwwroot/.python_packages/lib/site-packages/uamqp/__init__.py", line 12, in <module> from uamqp import c_uamqp # pylint: disable=import-self

At first, my function was running from a __init__.py as default file created by visual studio code. So I thought it might be a name clashing. So I changed my file name to testServiceBus.py but I still have the same error.

this is my full configuration.

function.json

{
  "scriptFile": "testServiceBus.py",
  "entryPoint": "main",
  "bindings": [
    {
      "name": "message",
      "type": "serviceBusTrigger",
      "direction": "in",
      "topicName": "XXX",
      "subscriptionName": "XXX",
      "connection": "XXX"
    }
  ]
}

host.json

{
  "version": "2.0",
  "extensions": {
    "serviceBus": {
      "messageHandlerOptions": {
        "autoComplete": false
      }
    }
  },
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[2.*, 3.0.0)"
  }
}

thank you very much for any help or hint, totally lost here and I have no more ideas to try

Nayden Van
  • 1,133
  • 1
  • 23
  • 70
  • I feel like I am getting closer. I am not sure how to test this but I believe is a conflict issue between the import azure.service and the `fund.ServiceBusMessage` – Nayden Van Oct 14 '21 at 21:33
  • You can refer to a similar open issue on GitHub: [Azure Function Service Bus ImportError: cannot import name 'c_uamqp' from partially initialized module 'uamqp'](https://github.com/Azure/azure-uamqp-python/issues/281) – Ecstasy Oct 18 '21 at 07:43

0 Answers0