Your approach sounds extremely reasonable, and is the somewhat equivalent to the versioning that the maintainers of public APIs are forced to perform when making major upgrades. In this situation you (the maintainer) are in total control of the caller and called so you feel a more sophisticated solution would be possible.

In a situation where you are directly changing the message format for the queue it would be expected that you’d realize that changes to both the producer/consumer would be required. Considering a separate situation where instead you add extra fields to a class, you may not even initially think to look at an async task that serializes/json_encodes the class. If your consumer expects the fields to be present (or calls any method on the class which does) when dealing with an “old” message it MAY give unexpected results which are hard to predict, and something which normal testing wouldn’t pick up on.

As you say there is only a small probability of such an event occurring. However if you find yourself in a situation where the occurrence of something slow happening is so important for the user that they would prefer it to be working correctly than super fast, then you may be better off keeping it called synchronously.