Azure / azure-webjobs-sdk

Azure WebJobs SDK
MIT License
737 stars 357 forks source link

ServiceBusTrigger scheduled message is undefined when read from the queue #2171

Open itair-miguel opened 5 years ago

itair-miguel commented 5 years ago

When sending a scheduled message to service bus queue, when the message is passed on to the queue itself and an Azure Function is triggered (Service Bus Queue Trigger) the message is undefined.

Repro steps

I am using https://github.com/Azure/azure-sdk-for-js for sending messages to the queue:

  1. Step A
public static async sendMessage(content: MessageDTO): Promise<string> {

    const ns = AzureServiceBus.createConnection();
    const client = ns.createQueueClient("" + process.env.AZURE_SERVICEBUS_SMS_QUEUE);
    const sender = client.createSender();
    let resp = "";

    try {
        const scheduledEnqueueTimeUtc = moment().utc().add(1, "m").toDate();
        const long = await sender.scheduleMessage(scheduledEnqueueTimeUtc, {body: JSON.stringify(content), label: "Change"});
        resp = long.toString();
        await client.close();
    } catch (error) {
        winston.warn("Was not possible to send sms for changeId: " + content.changeId);
    } finally {
        await ns.close();
    }

    return resp;
}

private static createConnection(): ServiceBusClient {
    winston.info("Creating connection on AZURE SERVICE BUS");
    try {
        return ServiceBusClient.createFromConnectionString("" + process.env.AZURE_SERVICEBUS_CONNECTION_STRING);
    } catch (err) {
        winston.error("Failed to create connection on AZURE SERVICE BUS", err.stack);
        throw err;
    }
}
  1. Step B

Receiving it on an azure function:

module.exports = async function (context, mySbMsg) {
    context.log("JavaScript ServiceBus queue trigger function processed message", JSON.stringify(mySbMsg));
};

Expected behavior

mySbMsg should not be undefined

Actual behavior

When the function is triggered mySbMsg is undefined:

bindings: Object {mySbMsg: undefined}

Known workarounds

Putting my message on the label as in:

const message: SendableMessageInfo = {
        body: JSON.stringify(content),
        label: JSON.stringify(content),
};

Allows me to read the message from:

module.exports = async function (context, mySbMsg) {
    const msg = mySbMsg ? JSON.parse(mySbMsg) : context.bindingData.label;
    context.log("JavaScript ServiceBus queue trigger function processed message", msg);
}

Related information

Also opened this issue on #https://github.com/Azure/azure-sdk-for-js/issues/2144 and was suggested that I opened it up here as well as it might be a problem on the service bus trigger itself not being able to do the binding in a proper way.

AlexZhidkov commented 5 years ago

I have the same issue. https://stackoverflow.com/questions/56373956/azure-service-bus-scheduled-message-in-binding-undefined

AlexZhidkov commented 5 years ago

@mathewc @brettsam Would somebody be able to have a look at this issue?

mathewc commented 5 years ago

Hmmm, perhaps related to https://github.com/Azure/azure-webjobs-sdk/pull/2211. Can you try setting an "application/json" content type on the message if it isn't already being specified?

AlexZhidkov commented 5 years ago

@mathewc I'm using @azure/service-bus to send message. I set contentType on SendableMessageInfo to "application/json" and it didn't change anything :(

yann-h commented 5 years ago

Workaround:

sender.send({
    messageId: "...",
    partitionKey: "...",
    scheduledEnqueueTimeUtc: ...,
    body: { ... }
})
ninjavang commented 4 years ago

Have been wrestling with the same problem for some time. Running an express-server that communicates with a couple of .NET-microservices through the service bus. Everything worked great until trying to schedule a message.

As I need to be able to cancel my messages, sender.send() is not a solution. I did manage to find my body hidden deep within the object in the .NET-service though, so if anyone else has the same problem, here is the solution that worked for me:

object body = message.SystemProperties
    .GetType()
    .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
    .Single(prop => prop.Name == "BodyObject")
    .GetValue(message.SystemProperties, null);

I'm mainly a nodejs-developer so if someone more comfortable in C# wanna improve on that code, please do!

meds commented 4 years ago

I seem to be having this problem too, sending a scheduled message through the queue client and then recieving an empty mySbMsg object in the srvice bus function (same azure functions project).

Seems odd this doesn't work, makes the whole service bus queue trigger useless, it's effectively broken and should be a higher priority to fix surely?

Then again there's still no way to delete queued messages using the nodejs sdk so clearly the whole library is an afterthought..

HarshaNalluru commented 4 years ago

Hey @itair-miguel,

Very sorry for the late response. The issue is caused by a bug in the service-bus JS SDK.

Cause - Expected encoding was not being done in the scheduleMessage() method as opposed to the send() method.

While the issue occurred with the Azure Function Triggers, it is not the case when received the message with Receiver.registerMessageHandler() from the JS SDK, which is the reason why the bug wasn't discovered till now.

Workaround

Please look at https://github.com/Azure/azure-sdk-for-js/issues/6816#issuecomment-574461068 for more reference.

Also responded at the issue that you have created here - https://github.com/Azure/azure-sdk-for-js/issues/2144 More Reference and Investigation around the bug - https://github.com/Azure/azure-sdk-for-js/issues/6816#issuecomment-574461068

/cc - @AlexZhidkov @mathewc @yann-h @ninjavang @meds