Best way to check message size before sending

NServiceBus v6.3.4

Hi Everyone, I am trying to send a message which is under the 4MB size limit of MSMQ. I first serialize the payload object using JsonConvert.SerializeObject(obj) and check its length. If it’s greater than 3.5MB, then I convert the object to byte[] and set the message DataBus Property otherwise I leave it alone.

I then do a context.Send() and immediately get a failed to send Message to addres: xxxx
System.Messaging.MessageQueueException: Insufficient resources to perform operation.

NSB does create header information for the message but it’s not 500k. Am I checking the size of the message correctly before I send it over the line?

Any help would be greatly appreciated.

Just as a side note, if I do place the object into the Databus property, the message goes through the bus just fine. It writes the file to the Databus directory but the size of the message is still under 4MB.

Thanks in advance.

Hi,

Can you elaborate your use case on the need to perform a check on the size?
Would it be a problem just to use data bus as is?

Other alternatives to DataBus is a community backed project:

Cheers,
Indu Alagarsamy
Particular Software

Hi Indu, Using the databus for every message would be a needless waste of disk space and with 10’s of thousands of messages each day it would not be an ideal solution. A check is made to ensure we only have to use the databus when necessary. What would be great is if NSB could do this for you. Unless I am missing something, you have to explicitly use the databus for large messages (>4MB), couldn’t NSB do a check before sending and use the databus property when necessary. That would remove the need for users making the check.

The fileshare link is an interesting concept and I will have to look into it. However the majority of the time, we just have a large message with no file attachments.

I can send the JSON of the message we are having issues with if that would help. It is clearly under the 4MB limit when I send but get an exception when doing the context.Send()

Thanks

-Len

I’m curious as to why this message is so big? is it due to some integration standard? or is there “many items” of some kind in the message?

Can you share the business use case that you’re trying to implement?

Hi Andreas. Sure. The messages in question are used to generate Adobe pdf files. The message contains all the information in order to generate said documents and includes a fairly large amount of XML. The original message sent contains about 3.0 MB of XML and other various pieces of data. (I know that is a lot of data that could be compressed or turned into JSON but that is another discussion :slight_smile: ) When the Adobe server generates the document, it returns a byte array of roughly 500KB. which we stuff into the original message and pass it along to its next destination in the workflow. Before sending it onto the bus however, we check it size. So original message of 3MB of XML and other pieces of data + 500KB of byte[] data is less than 4MB. Serializing the entire message yields a size of roughly 3,523,650 of byte[] data. Because it is under 4MB limit, the databus property is not used, however when the message is sent using the context.Send() we get the following error:

System.Messaging.MessageQueueException: Insufficient resources to perform operation.
at System.Messaging.MessageQueue.SendInternal(Object obj, MessageQueueTransac
tion internalTransaction, MessageQueueTransactionType transactionType)
at System.Messaging.MessageQueue.Send(Object obj, String label, MessageQueueT
ransaction transaction, MessageQueueTransactionType transactionType)…

Just as a test… If I take the message contents and write it to the databus property and send the message it goes through the bus without any issues, In the Databus directory, I get a file that is 3.67 MB (which is still under 4MB). This whole thing is very vexing.

Thanks

-Len

Sounds like you’re moving data around using messaging. Could you have the adobe server store the payload on a fileshare, azure blob, s3 bucket etc and just pass the “link” in the message?

That way that data will travel as little as possible on your network so that would be the most efficient solution?

The Adobe services will need to be updated in order to do that (which is another technical debt item on a very long list). The current workflow works more than 99% of the time. Generally the service will return data that is quite large (50+MB) for documents that are 200+ pages in size which are very rare or very small (< 100KB single page documents about 99% of docs generated fall into this category).

It seems there is a sweet spot of Message Size + Document Size + some other delta that needs to be accounted for and I can’t figure out that delta. The way I’ve been able to get around it by making the maximum message size smaller.

 if (encodedContents.Length > NavBus.MAX_MESSAGE_SIZE)
 {
      _contents = "Encoded to DataBus";
      _contentsDataBus = new DataBusProperty<byte[]>(encodedContents);
 }
else
{
      _contents = contents;
}

where MAX_MESSAGE_SIZE is 3,250,000 bytes

-Len

You are reaching the message size limit because the binary is not stored binary in a JSON message.

It probably is encoded as Base64 which increases the size of the JSON document. A Base64 encoded string more or less uses 4/3 of the byte array.

Potentially you can also select a more efficient serializer that uses a binary format which will not expand binary data via Base64:

Alternatively you can use BSON:

I’m not 100% but I think this will store binary data efficiently.

Thanks Ramon. You are exactly right. I’ll dig more into this.

I found this very interesting thread here…

Binary Data in JSON

which talks extensively about it.

I appreciate all your help Particular.

-Len