The coupling is already there, putting messages in between doesn’t resolve the coupling. There’s no way you can receive the price without a proper token, not even if pigeons start delivering the tokens.
I have zero context related to your scenario, but I hear that argument a lot and hardly ever anyone had to act on it. But even then, abstract away the storage/retrieval of the tokens and replace the implementation behind the abstraction. Repository pattern could indeed be an option.
Not really. But I’d indeed probably never implement it this way. Rather use the option of directly retrieving the token inside the same endpoint.
The long answer:
Not really. Same answer as above, but here’s more explanation for possible scenarios. There are multiple possible ‘retries’, with lack of a better word.
- A customer needs to pay an order but doesn’t have enough money
- A customer needs to pay an order but primary creditcard fails and has secondary creditcard
- A customer needs to pay an order but the 3rd party service can’t be contacted
The first is clearly a business process. The message handler for processing the payment receives some sort of notification from the bank and needs to report this to whoever controls the order, in our case via a message. The handler responsible for the order could cancel shipment, or email the customer about this and give the customer 10 days to enter different kind of payment method. It all depends on how the business wants to treat this.
The third is clearly a technical issue. Right?
But imagine that there’s a message handler waiting for a response. This is not just a matter of “Try immediately 3 times and then 3 times more with delayed retries. If all fails, move it to the error queue”. The business might want a response from the payment message handler within 10 minutes? A saga could be set up that, if the payment message handler doesn’t provide within 10 minutes, we’ll try something else. Like give up and email the customer?
The second might not seem a clear cut business process. But it’s closer to your example. It might fail because there’s not enough money, but it might also be that the 3rd party service for CreditCard-1 is unavailable. Do we differentiate between technical failure and lack of money here? Because the saga waiting for an answer, again, might make a decision of its own after 10 minutes. I would not wait for both the first creditcard to fail and initiate the second creditcard. That’s the responsibility of the payment endpoint, not the saga inside the order endpoint, or whatever they’re called.
Even though the payment might fail because of technical reasons (the service is unavailable) or because there’s not enough money, trying for the second creditcard is simply part of (potentially) a saga and 1 or more messages being sent.
I would say the same for your scenario. Even though the token expired, this should not go into retries, because it’s not a transient failure or similar. This will never fix itself, unless we retrieve another token. And we can only retrieve another token by letting the sender of the token (in your case the saga) know that we need a new one.
But again, I’d implement retrieving the token and retrieving the data inside the same endpoint.
Think of it like logging. Would you send log-entries via messages and queues, because otherwise the endpoint would be tightly coupled to the logging engine? The coupling is already there, don’t fight it