title: Chargeable Web Service with long running operations - Transactional design
body: <p>I'm creating a WCF Web Service which wraps calls to another remote API, and is chargeable.</p>
  
  <p>I want to make this a Synchronous service for ease of the client, and also because 99% of the time, the remote API will respond quickly and so there will be no discernible delay to the client.</p>
  
  <p>I also want to make the service chargeable.  Clients will be able to deposit money on their account, and then each service call will be charged, if successful.</p>
  
  <p>Obviously, I need to ensure that when each request comes in, enough money is on account in order for the call to take place.</p>
  
  <p>My plan and current prototype does the following:</p>
  
  <ul>
  <li>Call a Store Procedure to check the Client's balance, and if enough, deduct the amount required for this request.  This SProc contains a Transaction and uses ROWLOCK and HOLDLOCK to make sure that the Client's balance is only read/updated one at a time.</li>
  <li>If managed to charge ok, carry out operations/Remote API calls required.</li>
  <li>If operations/Remote API failed, refund the amount to the Client's balance (again Transactional, locked update SProc)</li>
  <li>If all was ok, mark the call as complete in the DB</li>
  </ul>
  
  <p>By doing it this way, I can allow a Client to make concurrent requests, and the only bottleneck (I think!) is during the balance check.  </p>
  
  <p>My thought process was that wrapping the whole call in a c# Transaction would mean that Clients would only be able to make a single call at a time.</p>
  
  <p><strong>Can anyone foresee any problems with this mechanism, or suggest better ways of designing it?</strong></p>
  
  <p>The one problem I can see is that if the first part completes and the Client is billed, but something <em>catastrophic</em> occurs during the operations/Remote API calls and the refund does not take place then the charge will have occurred for an incomplete call.  I would be able to detect these as there would be no Complete or Refunded marker against the call, and would have to deal with them "off-line".</p>