I have the following problem:
Our system has products that when released only are allowed to be purchased X times. Upon purchase a central purchasing algorithm checks how many Orders exist and if below X proceeds with the purchase.
In pseudoish C# code:
public class OrderMethods
{
public static Purchase(Product product, Client client)
{
int purchases = /* count order records of this product */;
if(purchases>=MAX_ORDERS) throw PurchaseException();
/* perform purchase by inserting order record in database */
}
}
The problem is that sometimes when there’s a high demand for a certain product a lot of request happen at the same time and more than MAX_ORDERS are registered. This happens about once a year :(.
What’s the best solution for solving this? I’m using ASP.NET/C#, Ling2SQL and MSSQL. We have 1000> orders per day. It’s important that orders are processed in the order they are requested.
The solutions I’ve comeup with so far:
-
One global mutex?
-
One mutex per product stored in a hashtable with an access function like:
private Mutex GetPurchaseMutex(Guid productId) { if (mutexTbl[productId] == null) { mutexTbl[productId] = new Mutex(); } return (Mutex)mutexTbl[productId]; }
Where mutexTbl is an Hashtable. Here I haven’t figure out how discard old mutexes in a nice way though.
-
Using a T-SQL INSERT Trigger on the Order table that checks how many orders there are:
CREATE TRIGGER Triggers_OrderInsertTrigger ON Orders
AFTER INSERT
AS
IF /* check if there’s to many orders */ BEGIN
RAISERROR (‘Too many orders’, 16, 1);
ROLLBACK TRANSACTION;
RETURN
END;
But I’m not so fond of either of these solutions. How would you solve this?
I’d say move this logic to the database layer when it can be secured with transactions.
Check for the number of placed offers and if okay place a new order within the same transaction. During this time the new requests will have their transactions (querying the number of placed orders) halted until the first is finished.