How to implement "SQL Transactions" in "Clean Architecture"? - mysql

I am working on an Express-based (Nodejs) API that uses MySQL for data persistence. I have tried to follow the CLEAN ARCHITECTURE proposed by Sir R.C. Martin.
Long story short:-
There are some crop vendors and some users. A user can request an order of some crops with a defined quantity from a vendor. This puts the order in PENDING state. Then the vendor will confirm the orders he/she gets from the user.
Domain/Entity -> CROP, Use-case -> add, remove, edit, find, updateQty
Domain/Entity -> ORDER, Use-case -> request, confirm, cancel
I have to implement a confirm order functionality
I have an already recorded order with ordered item list in my DB (order in the pending state)
Now on confirming order action I need to subtract each item quantity from respective crop present in the DB record, with a check that no value turns negative (i.e. no ordered qty is more than present qty)
If it is done for all the items under a "transaction cover" then I have to commit the transaction
Else revert back to the previous state (i.e rollback)
I know how to run Mysql specific transactions using "Sequelize", but with a lot of coupling and poor source code architecture. (If I do it that way, then DB won't be like plugin anymore)
I am not able to understand how to do this while maintaining the architecture and at what layer to implement this transaction thing, use-case/data-access, or what?
Thanks in advance

I recommend keeping the transaction in the "adapters layer" by using "unit of work" pattern. This way the database remains a plug-in to the business logic.

Related

How to avoid paying for the same item multiple times

I'm trying to draw a database design of an ecommerce, and fulfilment of order platform. The company currently has a distribution centre for fulfilling the orders. But they want to extend this to use its stores for a part of the fulfilment process. I have designed a database of "internet sales" and "store sales", but I am stuck on the fulfilment of the internet order, and I wonder if any of you can help me with this.
Scenario : When the customer places in an order, and the distribution centre doesn't have a stock of an item to ship to the customers, the item needs to be taken from one of the stores. This item is then sent to the customer.
But the problem is that I can't just take an item from a store, and then send it to the customers, because the item hasn't been sold in the store, its (store) stock database isn't going to be updated. If I put the item through the cash machine, the item is removed from the stock table, but there are two transactions for the same item - one transaction from the internet, and the other from the store.
I guess my question is, how do I go about processing internet orders, and avoid having two transactions on the same item?
Any helpful pointers on this issue is greatly appreciated.
Update : Here's what I have done so far after advice from Jo Douglass,
Database Design Here
Sorry, I can't post images, because I don't have enough points. And please note that the above database design isn't complete
It sounds like you have a Transaction entity, and you have or are planning on having some logic which ensures that when one of these is created for an Item, your system knows to deplete the stock level for the relevant location (either a store of the distribution centre).
You could use an entity which shows an Item being transferred from one location (a store) to another (a distribution centre), and then create some logic which works very similarly to your existing logic - depleting the stock level in the starting location, and increasing the stock level in your destination location. Then when you carry out the last part of the process (sending the item to the customer), you'll have a Transaction showing that and depleting the distribution centre's stock level. Depending on the rest of your model, you might carry this out via a change to the Transaction entity, or by creating a new entity altogether.
Alternatively, if that doesn't really model what's happening in the business very well, then maybe you just need to modify your logic (and possibly your model - hard to tell without seeing your existing model). Rather than only being able to create store transactions via use of the cash register, perhaps you simply need to be able to create a store transaction that's been kicked off via the Internet.
One idea is to go ahead and treat the item as sold from the store (through an online transaction) and credit the store's account with the sale price. The distributor has probably already received the wholesale price from the store so it's happy, the store gets credit for the sale (with at least some part of the shipping charges) so it's happy, and you don't have to create new transaction codes or any other modification to the existing database.

Store static transaction details as JSON in MySQL

My application generates payments to contractors based on a number of different objects on our platform. For example, we have jobs and line items per job. Each of those have their own details.
After we pay out a contractor, sometimes job details are changed around, for whatever reason, so sometimes we'll have a generated (email) receipt that says one thing but the job details queried from the database say something else.
I've been thinking about saving the current job details as JSON as storing it in a text field for each payment, so that we have a "snapshot" of the object at the time it was paid.
a) Does something like that make sense to do? Or would it be better to lock old jobs so they aren't editable anymore?
b) If it does make sense, would it be worth it/useful to store it in something like MongoDB? Would it be less complicated to just keep it all in mysql?

Preventing race conditions for ecommerce application with MySQL

I'm building a ecommerce application with MySQL, but I'm having a hard time coming up with a solution that prevents the following race condition:
Two users checkout at the same time with the same item in their cart. The store only has one item available for sale. One user should be able to purchase the last item, and the other user should see an error message because the item is out of stock.
I'm using an item counter to keep track of the number of items in inventory, so I figure I would just decrement the item after processing the user's credit card.
I know about the SELECT...UPDATE query in MySQL, but I'd like to stay away from locking rows or tables - unless that's really the best way for an ecommerce app to solve this problem.
I'm also interested in hearing other solutions other than checking/decrementing an item counter.
Why are worried about locking. It wont hurt you till you have 100s of simultaneous customers at a time and database engines like innodb are made to handle those things. You wont be able to get way from some kind of atomicity and workaround.
You need to keep application level transaction management.
checkout
reserver_the_items_in_cart
if(reservation_succesfull){
get_the_payments_done_via_payment_gatway
if(payment_successful) {
update_the_reserverd_to to sold_status
}else{
make_reserved_item_to_available.
}
}else{
show_error_that_item_not_available.
}
Other best way to handle this is never allow "show_error_that_item_not_available" to happen. Replenish inventory on time when it started running out.
The way I am going about this is
1. check availability for X books
2. if there are X books, place the actual order
3. check availability again if availability is ok, then everything is ok... if availability is off, I reverse the order and notify customer.

What should your transaction management strategy be for an e-commerce system?

What is the general pattern or approach to managing transactions in a web-based e-commerce system? How do you handle the situation where more than one user tries to buy the last item, for example?
To prevent two users from purchasing the same stock item of which there is only 1 unit in stock, you need to check that each item in a user's cart has stock available right before you create an order and decrement stock for that item.
This operation will have to be atomic and only one order can be processed at any given time (read: database transaction), which should not be a problem if you are using a central database for stock management.
If stock has run out by the time a client checks out, you should remove the item from the client's cart and redirect them to their shopping cart, informing them of the situation.
Of course, this situation only occurs when two users both add the same stock item to their cart of which only one unit is in stock and one of them checks out. First come, first served. You should generally not allow clients to add products to their cart if no stock is available at that moment, unless you can order new stock within a reasonable amount of time, but in that case, the whole point is moot.
You can take a preemptive approach by checking that stock is available the moment a client initiates checkout and take the same route as above. However, that would depend on the nature of your product and the volume of transactions vs cancelled orders. If it is likely that another order for the same item was cancelled in the meantime and stock becomes available by the time a client checks out, then you don't want to lose a sale by telling the client that no stock is available. Better to let the order fail at the moment stock is not available and inform the client of the situation, which is rare after all.
Why not take the order and then get that item for the customer, perhaps a bit later? You can win a repeat customer :)

Techniques for adding Achievements to business class software

I was thinking of adding some Achievements to our internal bug-tracking and time logging system. It's connected to an SQL Server back-end.
At first I thought that the system could be run on the database, using triggers to, for example, know when:
you've logged 1000 hours
created 1000 tickets
closed your own ticket
worked on a ticket that has been not touched in a while.
etc (you know - database-ish things)
But then I realized that I would also want purely front-end achivements
used the advanced search abiltiy
sorted by a column
reset settings to default
searched 500 times
It seems like the logic of every achievement must be hand coded. Could anyone imagine an some sort of Achievements Rules Engine, that you for example create scripts for?
And how to store them? If the achievement is:
change column sort order 50 times in one session
that would imply that every time they sort a listview column it updates the database.
Any thoughts on this Win32 application design problem? I don't think that the Gang of Four have an Achievements design pattern.
Note: It's a Win32 client application, not a web-site.
i definetly like the idea of an eventing system. Various actions the user takes can raise events through a single eventing object:
protected void TimeEntriesListView_ColumnSort(object sender, EventArgs e)
{
_globalListener.RaiseEvent(EventType.ListViewColumnSort, sender, e);
}
protected void TimeEntriesListView_ColumnDrag(object sender, EventArgs e)
{
_globalListener.RaiseEvent(EventType.ListViewColumnDrag, sender, e);
}
That object can then have logic added to it to decide which events it wants to count. But more reasonably, various event listeners can attached to the central event listener, and have their custom achievement logic.
The trick isn't the coding of the rules, really, those are straightforward, and can perhaps be simple expressions (number_of_bugs > 1000).
The trick is accumulating the statistics. You should look at a form of Event Stream Processing to record your achievements. For example, you don't really want to implement the "1000 bugs" achievement with "select count(*) from bugs where user= :user" all the time (you could do it this way, but arguably shouldn't). Rather you should get an event every time they post a bug, and you achievement system records "found another bug". Then the rule can check the "number_of_bugs > 1000".
Obviously you may need to "prime the pump" so to speak, setting the number_of_bugs to the current number in the DB when you start the achievement system up.
But the goal is to keep the actual event processing light weight, so let it track the events as they go by with all of the events running on a common, internal pipe or bus.
A scripting language is a good idea as well, as they can easily evaluate both expressions and more complicated logic. "number_of_bugs > 1000" is a perfectly valid Javascript program for example. The game is just getting the environment set up.
You can also store the scripts in the DB and make an "achievement" editor to add them on the fly if you like, assuming you're capturing all of the relevant events.
I am also trying to figure out how to build an achievements rules engine.
I checked around rules engines and what are the basics of it. There is a good summary of that in wikipedia
Basically, you either have foward chaining when you, for example, check availability for something; otherwise, you use Event Condition Action rules. Its the latest that caught my attention.
So you could predefine a set of triggered events. In the engine you can define what are the checked conditions who are based on available metrics, and specify the association achievement.
This way seems more flexible, but you have to define the events, possible condition checks and metrics.
For example, you would have various events like TicketCreated triggered in the code.
In the rule engine you could have something like
Event: TicketCreated
Condition: UserTicketCount >= 1000
Achivement: "Created 1000 tickets"
or for "reset settings to default"
Event: SettingsChanged
Condition: Settings = DEFAULT
Achievement: "Reset to Default"
I haven't tried it yet, but I'm going to pretty soon. It's mostly theoric for now.
The backend achievements should be simple - they seem to be based on already tracked items. The front end, as you correctly stated, will require more tracking. One way you might want to do this is implement an analytics engine for your front end site.
Piwik at http://www.piwik.org might help here - it is a google analytics clone, that you host yourself. The idea would be to use it's logging capabilities to track when an achievement has been completed.
As for some form of scripting of the rules, you will always have to hand code them - you can perhaps make it simpler though, by creating your own small scripting engine, or implementing a custom Lua set.
How about storing the sql query associated with the achievement in the database itself, so adding a new achievement would only involve adding the name and the sql query for it.
for e.g.
you've logged 1000 hours - "select case sum(hours) > 1000 then 'true' else ' false' end from user where user_id = ?"
The UI based achievements would have to have the data stored in the db as well because you may use the same data for other achievements going forward.
I think one table to hold each event that you want to track. Such as "Performed a search". Then each achievement could have an SQL associated with it.
You could then build one trigger, on the Event table, which would compare the achievements that apply to that event, and add the achievement to the Achivement table.
Here are the quickie table designs:
EventItems:
UserId, EventName, DateOccured, AnyOtherInfo
AchievementQualifiers:
Achievement Name, AchievementCheckSQL, EventsThisAppliesTo
(Normalize this, if multiple events apply)
In you System, weather its web or win32, you simply insert into the EventItems table whenever the user does some event that you want to track. You could make one class to handle this. For purely DB type events, such as "Item Posted" or "Comment Posted" you could do this with a trigger instead.
Then, in the triggers on EventItems, for each AchievementQualifer that has that EventThisAppliesTo, run the SQL check, and update an UserAchievement table if it's true and hasn't been awarded yet.
Excuse my spelling, as I'm typing this while sitting in a brew pub.