azure-functions-host icon indicating copy to clipboard operation
azure-functions-host copied to clipboard

Service Bus Output Binding is creating multiple messages from a JSON array when returning a string

Open blockingHD opened this issue 1 year ago • 9 comments

Service bus output binding creating multiple messages when returning a string which is a JSON array. This has been noted since updating to .Net 8 and using the dotnet-isolated function runtime. This behaviour has changed either between .Net upgrades or moving to isolated functions.

Repro steps

Run the following function:

[Function("Test Func")]
[ServiceBusOutput("queuName", Connection = "ServiceBusConnectionString")]
public static async Task<string> RunAsync(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req)
{
    return await req.ReadAsStringAsync();
}

Call with this JSON payload:

[
  {
    "Test1": "test1"
  },
  {
    "Test2": "test2"
  }
]

Expected behavior

A message is created with the body:

[
  {
    "Test1": "test1"
  },
  {
    "Test2": "test2"
  }
]

Actual behavior

Two messages are created:

{
  "Test1": "test1"
}
{
  "Test2": "test2"
}

Related information

Provide any related information

  • Programming language used: C#
  • Bindings used: HttpTrigger - ServiceBusOutputBinding

blockingHD avatar Jan 18 '24 15:01 blockingHD

Note that this documentation: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output?tabs=python-v2%2Cisolated-process%2Cnodejs-v4%2Cextensionv5&pivots=programming-language-csharp states that to place a single message string, byte[], JSON serializable types should be used and for multiple messages T[] where T is one of the single message types should be used instead.

blockingHD avatar Jan 18 '24 15:01 blockingHD

I believe this is expected, the docs say to use string only if it's "simple":

"The message as a string. Use when the message is simple text."

A JSON payload would not be considered a simple string in this case.

You should be able to use byte[] or POCO for this instead. Alternatively, you can escape the json string and it would end up as one message e.g. "[\n {\n \"Test1\": \"test1\"\n },\n {\n \"Test2\": \"test2\"\n }\n]"

liliankasem avatar Apr 05 '24 19:04 liliankasem

The issue is the difference in behaviour between the in process and isolated models. When sending this via the in process model it is sent as a whole string whereas the isolated model sends it as separate messages.

Unfortunately the docs are ambiguous as simple string should be any string in my mind. Mainly because if I wanted multiple messages I would send an array of some description. Not helped by the same wording being present between the two models.

I have a continued case open with Microsoft and they have isolated the issue to the service bus extension SDK. It seems the engineering team are working out a way to make this work. Whether that be via configuration or a change to the SDK. The only workaround they have come back with is using the service bus SDK directly.

blockingHD avatar Apr 10 '24 06:04 blockingHD

Thanks for the context. If the SDK team was able to identify the issue and is working on a fix for it, there isn't an action item for the worker. But we can keep this issue open to validate the fix worked once it has been released.

liliankasem avatar Apr 10 '24 17:04 liliankasem

@blockingHD What was the result of the case with the SDK team?

satvu avatar Apr 03 '25 20:04 satvu

Notes: This is still reproducible, and it is not the functions host modifying this string.

satvu avatar Jul 30 '25 19:07 satvu

I tested this with a Node app as well, and I believe that the outlier is actually how in-process handles this kind of string. Node also splits that string into two.

I retract my statement that the host is not modifying the string - it's not doing so explicitly, but during the binding step (around here, I believe the string is parsed as a collection.

satvu avatar Sep 05 '25 22:09 satvu

Discussed this with the team - we need to have parity with in-process and fix this, but the resulting change would affect all language stacks. We need to have continued compatibility, but this would be a breaking change. Marking this as a design-stage item.

satvu avatar Sep 12 '25 17:09 satvu

I can confirm that python function app behaves in the same way by splitting json array to the separated messages. I guess the best way to solve the issue would be to add parameter to the service_bus_queue_output decorator.

sersol43 avatar Oct 20 '25 07:10 sersol43