Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

up vote 3 down vote accepted

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).

share|improve this answer
    
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. –  John Cartwright Apr 9 '13 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 Apr 9 '13 at 7:04

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.

share|improve this answer

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.

share|improve this answer
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. –  John Cartwright Apr 9 '13 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 Apr 9 '13 at 6:42

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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