Regardless of what kind of channel or medium of communication exists between two interfaces, when the producer modifies the format of the message that consumers know how to accept, there is a risk of change on clients.
The whole idea of using a AMQP broker is to be sure that the services can communicate with each other without them knowing each other. So the producer doesn't know the consumers. That's what is making this pretty confusing for me.
This isn't the reason one would use asynchronous message queuing in an application. This is the reason one would employ SOA (Service Oriented Architecture) and Microservice architecture. Think of message queues as merely a communication channel with some special properties like zero-message loss, guaranteed message delivery, asynchronous messaging, and easier ability to develop reversible transactions on a message.
The format of the message is essentially the contract that your producer and client agree to when exchanging messages. The client need not know about the inner workings of the producer, however it must be able to reason about the producer in terms of the contract. Software components are reasonably decoupled. This means that if the producer were persisting data to a database, then you could feasibly refactor the database, and as long as you don't change the format of the message then your clients are reasonably abstracted from this change thus minimizing the risks.
That is what Software Architecture is really all about. It is measuring and reasoning about qualitative attributes of software (modularity, composability, etc...) to make decisions and trade offs to mitigate risks.
If you must change the format of the message, then you are modifying the contract. The best way to proceed forward here is to take a disciplined approach.
- Formalize the format of your message. Structured formats like XML are good here because I can define an XML schema that I can use to enforce and validate a message.
- Version your XSD so that it is easier to reason with, identify, and describe clients that use your service.
- Stub the service with a mocking tool. You can do this with unit testing tools or something more sophisticated like SoapUI to emulate a provider message format change that hasn't been implemented yet.
- Perform proper unit and component testing of your clients against your stubbed interface and verify your use cases.
- Implement your provider change and then unit and component test this against your use cases.
- Perform system integration testing to verify that clients and providers are talking correctly to one another.