Imagine a little webshop which uses its own currency.
In the database, there is a table for items, which can be bought. The count of each item is limited. This limit is stored in a collumn in this table as integer.
Also, there is a table for the user's cash accounts, whereas for each account the current balance is saved.
If, for example, two users conduct their purchases at the same time and only one item is available, it could be possible that both users pay but only one receives the item due to racing conditions.
How can such racing conditions be resolved, without relying on entity framework throwing exceptions on saving?
How can I ensure the count of available items and the account balance of the buyer is correctly updated?
This isn't really a problem specific to Entity Framework, it's applicable to just about any shop scenario. It comes down to a question of policy - the only way to ensure that two customers do not purchase the same item is to allow a temporary lock to be placed on that item when they add the item to the cart, or begin the checkout process, similar to how concert tickets or flights are sold. This lock would expire if the purchase is not completed within a set amount of time, and the item would be released back for other customers to purchase.
In an e-commerce setting, this is not as suitable, since people may add an item to their cart and not check out, or spend extra time choosing additional items. This may lead to the scenario where you have items for sale but they can't be bought because they're in someone's cart who's not planning on checking out. Instead, duplicate orders are allowed, but payments are typically only pre-authorised and then completed at the time of shipping or order confirmation, so even if the second customer enters all their details and presses Buy, their card wouldn't be charged since the item wouldn't be shippable.
You can implement checks at different stages during the Checkout process to ensure the items in the cart are still available, or at the simplest level, leave it for the final "Pay Now" button on the last page. Ultimately though, this just reduces the potential for the race condition, rather than eliminating it.
Related
On my template i have a button to collect fee that takes the user to next screen. However, i want a check on this button's click event if the fee is already paid-in-full and prompts the user via message on screen.
In related model i have method that checks if fee is paid in full. I had added the condition on template like this and it disabled the button
<td>Add Fee</td>
but this increases the number of queries as i have a many students records on current view.
In general if i want such validations before user can go to new/assigned view, what would be the best practice.
Since you've asked for best practices followed, I will point out a few:
Pagination, use offset and limit for fetching the list of Students - have a look at index function here - thereby preventing too many database calls in one go.
Getting such information ideally shouldn't require extra DB calls, the table joins should suffice - thereby taking away the need for several database calls.
Note: I'm not suggesting changing the view/ user experience, as that would be out of the scope of this discussion.
I'm building a Django web application, part of it involves an online ordering system for food. I want to make a "receipt" object to save transactions.
My concern, however, is this - let's say I have an object Receipt that relates to Orders which relate to Items, if the items get edited or change over time, it will make the receipts look different down the line. Is there a way to save these at the moment of a transaction?
I am implementing a "soft deletion" to my models to avoid deletion issues however I don't think this would protect against edits.
The only way I can think of to deal with is to 'materialize' the Receipt. In other words when a receipt is generated use the Order and Items information current at the time and then write the actual values, not the Order/Items id to a receipt table. So for a Items item write out the attributes(description, price, qty.etc) you are interested in recording to the table, instead of just an Items.id that points to a possibly changed value in future.
I have a customer table in DynamoDB with basic attributes like name, dob, zipcode, email, etc. I want to add another attribute to it which will keep increasing with time. For example, each time the user clicks on a product (item), I want to add that to the record so that I have the full snapshot of the customer's profile in a single value indexed by the customerId. So, my new attribute would be called viewedItems and would be a list of itemIds viewed (along with the timestamp).
However, given the 4KB size limit for DynamoDB value, it is going to be surpassed with time as I keep adding the clicked products to the customer profile.
How can I best define my objects so as to perform the following?
Access the full profile of the customer by customerId, including the views.
Access time filtered profile of the customer (like all interactions since last N days), in which case the viewed items should be filtered by the given time range.
Scan the entire table with a time filter on viewedItems.
The query needs to be performant as the profile could be pulled at request time.
Ability to update individual customer record (via a batch job, for example, that updates each customer's record if need be).
One way to do this would be to create a different table (say customer_viewed_items) with hash key customerId and a range key timestamp with value being the itemId that the customer viewed. But this looks like an increasingly complicated schema - not to mention twice the cost involved in accessing the item. If I have to create another attribute based on (say) "bought" items, then I'll need to create another table. So, the solution I have in mind does not seem good to me.
Would really appreciate if you could help suggest a better schema/approach.
As soon as you really don't know how many items will be viewed by user (edge case - user opens all items sequentially, multiple times) - you cannot store this information in single dynamodb record.
The only solution is to normalize your database and create separate table like you've described.
Now, next question - how to minimize retrieval cost in such scheme? Usually you don't need to fetch all viewed items, probably you want to display some of them, then you need to fetch only last X.
You can cache such items in main table customer, ie - create field "lastXviewedItems" and updated it, so it contains only limited number of items without breaking size limit, of course for BI analysis - you will have to store them in 2nd table too.
I'm trying to figure out how companies that use nosql database solve this general nosql race condition issue:
Lucky example: User and Product. Product has quantity of 1 and there are 2 users. When the first user tries to buy this product, system first checks whether quantity is > 0 and it is indeed > 0, proceeds to create a Transaction object and decrement quantity of product. The second user tries to buy the product, system rejects as quantity isn't > 0.
Unlucky: Both users try to buy the product simultaneously. For both, system confirmed quantity is > 0 and so created a Transaction object for both users, hence destroying the company image next day...
How to generally deal with this common scenario?
From similar cases i found on the net, one suggested solution is to use request queue, and process the request one by one. However, if all transactions are queued, and you're running business like Amazon (millions of transactions every now and then), how do we expect users to know whether or not their purchase succeeded shortly after they clicked that purchase now button?
One of the ways to solve this problem is to allow both users to order products simultaneously.
Then there are two possible situations:
One of the users doesn't finish a transaction (refuses to pay, closes a browser window etc). Then another one will have the requested amount of a product.
Both users finished their transactions. Then you will get a random user your product and say sorry to another one giving away a coupon with $10 to him/her.
The second situation should happen extremely rare. So you won't blow out all your money on coupons and your users will be happy whatever the outcome. But you still need to monitor the 2nd situation in order to react and make changes to your system if it happens more often than you expected.
What are strategies to deal with seemingly common scenario of a limited inventory and an order form.
If there is one item left, and two people attempt to purchase at the same time. How do you deal with whoever submits payment last?
When a user adds a limited-supply item to their shopping cart, put a hold on the item for a small window of time - say, 15 minutes. It's theirs if they pay within the window, otherwise the hold is removed and the item is returned to the pool. (For the duration of the hold, the item considered "not available" to other users.)
AFAIK, it's pretty standard technique - I've seen Gilt do this, for instance.