6

In general, if I am using an API whose methods have side-effects that I only want to occur once, how can I guarantee that my own application only calls them once even if an error occurs before it can register a response?

For example, if I am calling a payment processing API once each month for a subscription service, how can I ensure that I don't double-bill if I create a new transaction and the application suffers a fatal error before I get the response from that? It seems like cooperation with the API would be a solution:

t = Transaction.new(user, price, etc);
if(t.persistToLocalDatabase()){ t.beginRemoteProcessing(); }

Is there a way to solve this for the case where I have no control over the API and it begins processing on transaction creation?

3 Answers 3

5

The first thing to do is to write a flag to disk before you start the transaction to indicate that this month's transaction has been attempted. That way you never accidentally call the API twice.

In the case of any kind of error, you need to make sure the system notifies a human (e.g. send an email) who can verify the transaction status and offers them a way to manually reprocess the transaction.

After a few months you'll discover either (a) The humans are bored of being contacted and you need to redesign the system (e.g find a way to automate the check/retry via the API) or (b) The system is running smoothly and everyone's happy. Hopefully (b).

2
  • This was the best that I could come up; ensure that failure could make the app not call the method at all. I'm hoping for some distributed computing solution but I'm not very optimistic there will be one. I'll accept this as the answer if nothing else turns up. Commented Apr 9, 2013 at 6:59
  • @JohnCartwright: Nothing else will come up. It's not possible without the API either gracefully ignoring second request or having separate method of finding out whether the request was handled.
    – Jan Hudec
    Commented Apr 9, 2013 at 7:04
10

If you are sending a request which can fail indistinguishably either before or after it's side-effects occur (as is the case of any network request where either request or response may get lost), there is no way to ensure the side-effects occur exactly once. Only either at most once (you don't retry) or at least once (you keep retrying until you get a response).

To get around this limitation, you need cooperation from the server side, i.e. the side where the side-effects occur. There are two options:

  • The operation should be idempotent. That is if it executes multiple times, the effects are the same as if it did just once.
  • You can inquire about status of the operation separately.

Both cases require that the data sent by client uniquely identify the transaction in some way. So than you generate the transaction data, persist them locally and send the request. If it is idempotent, you keep retrying until you get response. If it has separate query, you ignore the response and do the query, retrying the query until you get response for it, and retrying the request while the status is not carried out.

If the API does not support either, the only chance, as grahamparks suggested, is to report the error to human operator to fix things up by other means.

1
  • I think this a a good option, the client can store the transaction locally, assign to the transaction a idetifier, perhaps a guid, to identify the transaction that it will be send to the server. Before request the action, the client could ask to the server if the transaction is saved in the server side. If not, retry. If the server replies that the operations exists in the server, the client can delete the transaction or mark it as done locally. Commented Mar 23, 2023 at 9:00
-1

Use a variable to flag the call to the method. Check this immediately and return if the flag is set.

In C/C++ you can use a static local variable to store the flag.

2
  • 1
    It is not possible to set a flag if the application fails before the API method returns, although in this case it may have performed the side-effect once already. Commented Apr 9, 2013 at 6:39
  • 1
    static local variable is once per function and program execution while I strongly suspect the only sensible meaning of once is per object instance.
    – Jan Hudec
    Commented Apr 9, 2013 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.