Interrupting transactions in Codeigniter - codeigniter

i am using transactions in codeigniter and have a routine includes file operations.
To be more specific i want to delete files from file system and database. I want transaction to fail if file is not found. So how can i interrupt an ongoing transaction and make it fail manually? Would
$this->db->trans_status() = false;
be enough?? Or is this approach correct way to do it?
PS: transction started in a Controller and i'm checking file status in a Model..
Thanks in advance.

Yes it seems it works. Except the mistake
$this->db->trans_status() = false;
must be
$this->db->_trans_status = false;

Related

When to use transaction in laravel

I am currently making a turn based strategy game with laravel (mysql DB with InnoDB) engine and want to make sure that I don't have bugs due to race conditions, duplicate requests, bad actors etc...
Because these kind of bugs are hard to test, I wanted to get some clarification.
Many actions in the game can only occur once per turn, like buying a new unit. Here is a simplified bit of code for purchasing a unit.
$player = Player::find($player_id);
if($player->gold >= $unit_price && $player->has_purchased == false){
$player->has_purchased = true;
$player->gold -= $unit_price;
$player->save();
$unit = new Unit();
$unit->player_id = $player->id;
$unit->save();
}
So my concern would be if two threads both made it pass the if statement and then executed the block of code at the same time.
Is this a valid concern?
And would the solution be to wrap everything in a database transaction like https://betterprogramming.pub/using-database-transactions-in-laravel-8b62cd2f06a5 ?
This means that a good portion of my code will be wrapped around database transactions because I have a lot of instances that are variations of the above code for different actions.
Also there is a situation where multiple users will be able to update a value in the database so I want to avoid a situation where 2 users increment the value at the same time and it only gets incremented once.
Since you are using Laravel to presumably develop a web-based game, you can expect multiple concurrent connections to occur. A transaction is just one part of the equation. Transactions ensure operations are performed atomically, in your case it ensures that both the player and unit save are successful or both fail together, so you won't have the situation where the money is deducted but the unit is not granted.
However there is another facet to this, if there is a real possibility you have two separate requests for the same player coming in concurrently then you may also encounter a race condition. This is because a transaction is not a lock so two transactions can happen at the same time. The implication of this is (in your case) two checks happen on the same player instance to ensure enough gold is available, both succeed, and both deduct the same gold, however two distinct units are granted at the end (i.e. item duplication). To avoid this you'd use a lock to prevent other threads from obtaining the same player row/model, so your full code would be:
DB::transaction(function () use ($unit_price) {
$player = Player::where('id',$player_id)->lockForUpdate()->first();
if($player->gold >= $unit_price && $player->has_purchased == false){
$player->has_purchased = true;
$player->gold -= $unit_price;
$player->save();
$unit = new Unit();
$unit->player_id = $player->id;
$unit->save();
}
});
This will ensure any other threads trying to retrieve the same player will need to wait until the lock is released (which will happen at the end of the first request).
There's more nuances to deal with here as well like a player sending a duplicate request from double-clicking for example, and that can get a bit more complex.
For you purchase system, it's advisable to implement DB:transaction since it protects you from false records. Checkout the laravel docs for more information on this https://laravel.com/docs/9.x/database#database-transactions As for reactive data you need to keep track of, simply bind a variable to that data in your frontEnd, then use the variable to update your DB records.
In the case you need to exit if any exception or error occurs. If an exception is thrown the data will not save and rollback all the transactions. I recommand to use transactions as possible as you can. The basic format is:
DB::beginTransaction();
try {
// database actions like create, update etc.
DB::commit(); // finally commit to database
} catch (\Exception $e) {
DB::rollback(); // roll back if any error occurs
// something went wrong
}
See the laravel docs here

Laravel Observer or MySQL Trigger?

i'm feeling confused, which are best practices between laravel observer or MySQL Trigger.
In Laravel, My Code looks like
public function updated(My_Activity $my_activity)
{
$activity = new Activity_Log();
$activity->activity_id = $my_activity->id;
$activity->status = $my_activity->status;
$activity->description = $my_activity->description;
$activity->save();
}
In MySQL,
BEGIN
INSERT INTO Activity_Log
SET id = OLD.id, status = OLD.status, description = OLD.description
END
What is the best practice ? Is there a good impact for one of them in the future?
I prefer Laravel Observer option because it allows you to keep your business logic in your application (source control). Additionally you keep your business logic at the same abstraction level by using Eloquent.
For the same reason Laravel introduced a Task scheduler. It allows you to keep your cron entries under source control.
https://laravel.com/docs/5.5/scheduling
In the past, you may have generated a Cron entry for each task you
needed to schedule on your server. However, this can quickly become a
pain, because your task schedule is no longer in source control and
you must SSH into your server to add additional Cron entries.

Configure time of Laravel scheduler from the database

I've a Laravel 5.2 application, I'm using the scheduler to runs a script every 30 minutes by now. But I'm wondering if that time can be retrieved from the database, I want that the admin user configure that time from the webpage, I have the field in the database. But I'm not really sure if the scheduler can update that time from the database, so, is it possible?
Also, I setted:
->sendOutputTo("/var/www/html/laravelProject/public/output")
to save the output in a file named output, but it's not seems that is working even when the cron is executed, I checked the cron log files and there only shows that there is not MTA installed, but I don't want for the moments to send a e-mail, I just want to save the output in a file, so, what am I missing there?
You can use when
The when method may be used to limit the execution of a task based on the result of a given truth test.
$schedule->command('yourcommand:execute')->everyMinutes()->when(function () {
if($timefromdb){
return true;
}
else{
return false;
}
});
https://laravel.com/docs/master/scheduling#schedule-frequency-options

Magento function getMessages - how to detect if messages has been set

does anyone know how to detect it messages has been set?
I found the following in core/session:
public function getMessages($clear=false)
But how do I now check if there is a message, or not?
(we use it to invalidate cache)
You need to check the storage for each session namespace (catalog, checkout, core, customer, tag...) for the presence of messages. EE observes the core_session_abstract_add_message event and writes a cookie which can then be referenced to determine whether there are messages to display. If you are authorized, refer to Enterprise_PageCache_Model_Container_Messages.
Thanks to Bixi
Mage::getSingleton('core/session')->getMessages()->count()
IF > 0 we invalidate our FP Cache (or block)
You can do:
Mage::getSingleton('core/session')->getMessages();

How to know when a web page is loaded when using QtWebKit?

Both QWebFrame and QWebPage have void loadFinished(bool ok) signal which can be used to detect when a web page is completely loaded. The problem is when a web page has some content loaded asynchronously (ajax). How to know when the page is completely loaded in this case?
I haven't actually done this, but I think you may be able to achieve your solution using QNetworkAccessManager.
You can get the QNetworkAccessManager from your QWebPage using the networkAccessManager() function. QNetworkAccessManager has a signal finished ( QNetworkReply * reply ) which is fired whenever a file is requested by the QWebPage instance.
The finished signal gives you a QNetworkReply instance, from which you can get a copy of the original request made, in order to identify the request.
So, create a slot to attach to the finished signal, use the passed-in QNetworkReply's methods to figure out which file has just finished downloading and if it's your Ajax request, do whatever processing you need to do.
My only caveat is that I've never done this before, so I'm not 100% sure that it would work.
Another alternative might be to use QWebFrame's methods to insert objects into the page's object model and also insert some JavaScript which then notifies your object when the Ajax request is complete. This is a slightly hackier way of doing it, but should definitely work.
EDIT:
The second option seems better to me. The workflow is as follows:
Attach a slot to the QWebFrame::javascriptWindowObjectCleared() signal. At this point, call QWebFrame::evaluateJavascript() to add code similar to the following:
window.onload = function() { // page has fully loaded }
Put whatever code you need in that function. You might want to add a QObject to the page via QWebFrame::addToJavaScriptWindowObject() and then call a function on that object. This code will only execute when the page is fully loaded.
Hopefully this answers the question!
To check the load of specific element you can use a QTimer. Something like this in python:
#pyqtSlot()
def on_webView_loadFinished(self):
self.tObject = QTimer()
self.tObject.setInterval(1000)
self.tObject.setSingleShot(True)
self.tObject.timeout.connect(self.on_tObject_timeout)
self.tObject.start()
#pyqtSlot()
def on_tObject_timeout(self):
dElement = self.webView.page().currentFrame().documentElement()
element = dElement.findFirst("css selector")
if element.isNull():
self.tObject.start()
else:
print "Page loaded"
When your initial html/images/etc finishes loading, that's it. It is completely loaded. This fact doesn't change if you then decide to use some javascript to get some extra data, page views or whatever after the fact.
That said, what I suspect you want to do here is expose a QtScript object/interface to your view that you can invoke from your page's script, effectively providing a "callback" into your C++ once you've decided (from the page script) that you've have "completely loaded".
Hope this helps give you a direction to try...
The OP thought it was due to delayed AJAX requests but there also could be another reason that also explains why a very short time delay fixes the problem. There is a bug that causes the described behaviour:
https://bugreports.qt-project.org/browse/QTBUG-37377
To work around this problem the loadingFinished() signal must be connected using queued connection.

Resources