You are dealing with distributed processing. This means that you cannot guarantee that any message (method call, etc.) will arrive at the other end; a connection can always be dropped arbitrarily. Because of this, you need a mitigation strategy that is independent of any particular message.
One of these strategies is to use a reliable messaging system, which essentially sets up databases for storing message queues, which are then reliably transmitted in order (by sending a message marked with a sequence identifier several times until confirmation is received), but this is a lot overhead costs, and they should probably be kept for important things (such as financial transactions).
Another strategy is to use a distributed transaction manager, but they have pretty big problems (unless you are implementing a distributed consensus system and are not complicated and still have potential failure modes).
I think the easiest way is to reorganize what is considered final. Ask the client to contact the server to collect a temporary description of the operation that should be recorded on the server (including a unique identifier, such as a UUID), after which the client can send a short message that starts the commit; At this point, the server needs to register that it has started work on processing this UUID. If the answer cannot be sent, it is still after fixing. If any message is lost, it does not matter much: either before the start of the commit (in this case it did not happen, but can be repeated) or after that in this case there will be a permanent record in which it was taken, and so easily inform what happened ("I'm still working on it," "I succeeded," "I failed."). The only state the client needs to remember is the UUID, and this can be highlighted outside of the transaction (a wonderful UUID property, which, admittedly, is only probabilistically true, but the likelihood of the problem is really negligible).
source share