BTW, the fact that you’re creating a new Context for each Session (connection) and each Flow means that you partially avoided some very bad behaviour. Because otherwise each of your Sessions would be sharing the same Context, and therefore the same thread. And so all 10 of your queues’ Flows’ callbacks would be on the same thread. So posting to S3 would be completely serialized.
For consideration, if you wanted to build this all in one app, here’s how I might do it. I’ll explain using Java since it’s similar enough for this explanation.
One Context, One Session (connection). Multiple IFlows, each bound to their particular queue. The callback simply takes the message received and places it in a BlockingQueue / BlockingCollection and returns, does not ACK. Callback == nice and fast now. Then you can have multiple worker threads bound to this BlockingCollection object and POSTing to S3. Something similar to this: https://www.youtube.com/watch?v=5ilYW2VqTqQ
If you are concerned about ordering, then you could have 10 BlockingCollections, one for each queue, and one worker thread processing from each. This ensures messages are stuck into S3 in correct order… if that matters to you.