How to detect deadlocks in PostgreSQL when using PHP's pg_* functions? - php

I use transactions with PostgreSQL. Transactions are a necessary part of serious databasing. Transactions inevitably lead to "deadlocks". Deadlocks are logged as errors, as they are. I don't want to ever have any errors logged, so I need to handle these deadlocks. Deadlocks are allegedly handled by detecting them, suppressing the error and retrying the query until it goes through without a deadlock.
So far, so good.
Now begin the problems. I use pg_query_params() and pg_query() to send queries to PostgreSQL. Both of these return FALSE on failure, or a "query result resource" upon success. When a deadlock is detected by PostgreSQL, these functions thus return a FALSE and my PHP error log gets a bunch of noise about deadlocks.
The PHP manual says this about pg_last_error():
Error messages may be overwritten by internal PostgreSQL (libpq) function calls. It may not return an appropriate error message if multiple errors occur inside a PostgreSQL module function.
It's thus not reliable and cannot be used. It goes on to state:
Use pg_result_error(), pg_result_error_field(), pg_result_status() and pg_connection_status() for better error handling.
Having looked up those functions, I realize to my horror that (as it says):
Because pg_query() returns FALSE if the query fails, you must use pg_send_query() and pg_get_result() to get the result handle.
pg_send_query() and pg_send_query_params(), in turn, are asynchronous. I have no need for, nor understanding of, such "async" SQL queries. I don't understand how that is possible or why anyone would want it.
The end result is that, once again, I find myself painted into a corner where seemingly the only way out is to crawl through the chimney and get myself all dirty and messy.
It appears I'm forced to entirely abandon pg_query_params() and pg_query() just to be able to detect deadlocks. Can this really be the case? I can only imagine what new errors will arise from the SQL queries being sent "asynchronously" instead of in a "blocking", orderly manner.
Why does this always happen? Every time I try to do anything, no matter how basic or common, it always seems to be considered a "weird edge-case" to everyone else. Surely there must be a way to detect deadlocks other than jeopardizing my entire application's integrity by using these strange "async" functions which I hadn't even heard of until yesterday?
And even if I were to use them, it's still very unclear how exactly I would detect a deadlock. Do they expect me to parse the error and look for the English strings such as "deadlock"? That also doesn't seem right at all; it feels like a weird hack.
Is there really no proper, clean way to detect deadlocks so that they can be handled properly?
Simply suppressing the PHP error (by using a custom error logger and checking for the string) would only solve the problem of error log noise, but would not actually make the deadlocked queries retry, and thus they would never do their job and just be silently ignored.

If anyone cares, I ended up "abusing" the pg_send_* queries in an blocking manner, just to be able to properly grab the deadlock (and potentially other, future) errors. It's the only solution, albeit it made me feel more "dirty" than satisfied with the solution. Maybe seeing this self-answer will help somebody in the future to realize that it's a complete waste of time to try it any other way, because I did, and failed, for a very long time.

Related

Should I always set ignore_user_abort as true?

Until recently I wasn't even aware it was possible for PHP to abort a script due to user disconnect.
Anyways, it could cause some real trouble for my database if the script could just abort midway through. Like if I'm inserting rows into multiple tables that partially depend on each other and only half of it gets done, I'd have to get real defensive with my programming.
Oddly enough, I found that ignore_user_abort defaults to false (at least on my installation), which seems like the sort of thing that could confuse the hell out of developers not aware of this possibility when something goes wrong because of it.
So to make things easier, shouldn't I just always set it to true? Or are there a good reason why it defaults to false?
Passing true to ignore_user_abort() as its only parameter will instruct PHP that the script is not to be terminated even if your end-user closes their browser, has navigated away to another site, or has clicked Stop. This is useful if you have some important processing to do and you do not want to stop it even if your users click cancel, such as running a payment through on a credit card. You can of course also pass false to ignore_user_abort(), thereby making PHP exit when the user closes the connection.
For handling shutdown tasks, register_shutdown_function() is perfect, as it allows you to register with PHP a function to be run when script execution ends.so it depends on your project
Anyways, it could cause some real trouble for my database if the script could just abort midway through. Like if I'm inserting rows into multiple tables that partially depend on each other and only half of it gets done, I'd have to get real defensive with my programming.
This can happen with or without ignore_user_abort, and should be addressed using database transactions.
So to make things easier, shouldn't I just always set it to true? Or are there a good reason why it defaults to false?
Since people are typically writing PHP code for the web, ignoring a user abort means your server would be sitting around doing useless work that's never going to be of value. Enough of them and you might find your server bogged down on abandoned, long-running HTTP requests.
If you've got lots of long-running requests that should ignore a user abort, a queue is a much better approach.

When to check if a query completed successfully

When do you want to check to see if a query completed successfully? Often in code I see a mixed bag of either checking if a update/insert/delete statement completed successfully (e.g. if ($query) { echo 'success' } or no checking at all.
I googled to see what the recommended choice was, but didn't find any relevant results. Further, I also realize this question is quite subjective depending on how sensitive the data is. But at the same time, unless the coder made a seriously malformed query to begin with, what is the point of checking if a query completed?
if ($user->update_user($this->input->input_stream(), $info) === false) {
encode_response('error', $this->n_config->get('query_error'));
} else {
encode_response('success', Auth_lang::get('user_updated_successfully'));
}
Always. Always. Always check for errors. You cannot presume that one query has succeeded and then blindly stumble on to the next step or bad things will eventually happen.
The easiest way to check for errors is to have everything automatically checked: Enable exceptions. These will be fired if there's a problem, you won't have to manually check on each call. You will, however, have to figure out how and where to catch these so they don't blow up your whole application.
Programmers come from different backgrounds and have differing opinions on how to do these things, and some are just too lazy to bother doing them at all. In C code there's no such thing as exceptions, so those sorts of developers are used to testing for error codes. In Java exceptions are such an embedded part of the ecosystem they're a given and people use them judiciously.
PHP isn't sure what kind of a programming language it is, you can use exceptions if you want to and error codes if that's more your style. This is why you see an unusually high level of diversity in approaches to these things.

What is the correct way to use exceptions with PHP?

I have always the "return status code" method to manage errors. It seems that exceptions are nowdays the best formed way to manage errors.
But are they really the best way ? I have read stuff like exceptions are worst than GoTo
Do you know some good articles/posts/books about exceptions and error management?
If you program object orientated, maybe exceptions are better for you. If you write procedural, return values are the better way. It depends on your coding style etc.
Exceptions are about 10000x slower than returning a status/error code depending on the programming language. This is due to all the stack information being kept track of. That's the bad.
In general, you don't ever have to use exceptions. In fact, at one point, the only thing that existed was return codes.
The nice thing about exceptions is that they won't let a program continue unless they are dealt with correctly. Instead, the program crashes.
So, basically, if you are forgetful about handling status messages or are worried that others may not check return codes from your functions, exceptions stop the program and make you fix it. Although, I have seen a lot of inexperienced programmers catch the exception, not do anything about it, and then continue on. This is basically the same as ignoring the return code from a function.
One other nice thing about exceptions is that they "bubble up" automatically. Instead of having to pass back error codes through a long chain of functions, you could set up your try catch at the very top level and handle any error appropriately (assuming you didn't want anything else to happen in between). For example, if anything goes wrong, display an error page.

When to use Try Catch blocks

Ok, this might be a very noob question, but I find that PHP Documentation on that and several Internet Searches hasn't give me any idea about that.
When should I use try-catch blocks to improve my application?
I read someone saying that we should use try-catch blocks only to prevent fatal errors.
I read someone else saying that we should use it only on unexpected errors (wait what? unexpected? if they are unexpected errors how could I prevent them with try-catch? should I put all my application code inside a try block?).
Others simply say that try-catch blocks should be used everywhere because they can be also extended (extending the Exception class).
Finally someone says that PHP try-catch block are totally useless because they are very bad implemented. (On this I found a nice SO question about performance).
It seems to me that this topic is very strange and confused. Could someone lights me up?
It seems to me that this topic is very strange and confused. Could someone lights me up?
Definitely. I'm not a PHP user, but I might have a little insight after having worked with try/catch in ActionScript, Java, and JavaScript. Bear in mind though, that different languages and platforms encourage different uses for try/catch. That said...
The only times I'd recommend using try/catch is if you're using a native language function that
Can throw an error/exception
Does not give you any tools to detect whether you're about to do something stupid that would cause that error/exception. eg: In ActionScript, closing a loader that is not open will result in an error but the loader doesn't have an isOpen property to check so you're forced to wrap it in try/catch to silence an otherwise totally meaningless error.
The error/exception really is meaningless.
Let's take the examples you list and see how they square with that list.
I read someone saying that we should use try-catch blocks only to prevent fatal errors.
In the case of AS's loader.close() function, this is good advice. That's a fatal error, and all from an otherwise trivial misstep. On the other hand, virtually ALL errors in AS will bring your application to a halt. Would you then wrap them all in try/catch? Absolutely not! A "fatal error" is fatal for a reason. It means something terribly wrong has happened and for the application to continue on in a potentially "undefined" state is foolhardy. It's better to know an error happened and then fix it rather than just let it go.
I read someone else saying that we should use it only on unexpected errors
That's even worse. Those are presicely the errors you DON'T want to silence, because silencing them means that you're never going to find them. Maybe you're not swallowing them, though... maybe you're logging them. But why would you try/catch/log/continue as though nothing happened, allowing the program to run in a potentially dangerous and unexpected condition? Just let the error kick you in the teeth and then fix it. There's little more frustrating than trying to debug something that's wrong in a program that someone else wrote because they wrapped everything in a try/catch block and then neglected to log.
Others simply say that try-catch blocks should be used everywhere because they can be also extended (extending the Exception class).
There's potential merit to this if you're the one doing the throwing, and you're trying to alert yourself to an exceptional situation in your program... but why try/catch your own thrown error? Let it kick you in the teeth, then fix it so that you don't need to throw the error anymore.
Finally someone says that PHP try-catch block are totally useless because they are very bad implemented. (On this i find a nice SO question about performance).
Maybe so. I can't answer this one though.
So... this might be a bit of a religious question, and I'm certain people will disagree with me, but from my particular vantage point those are the lessons I've learned over the years about try/catch.
Different people will tell you different things. But this is what I think, specifically in the case of a web application.
Your whole page should be in a try/catch that displays an error message to the user. The error message shouldn't tell the user what happened in detail because thats a security concern. It should record information about the error into a log file.
The other case is where something could go wrong in the normal operation of affairs. PHP is not very exception happy so this may not happen very much. Basically, if you run into a function that throws an exception when it fails, you can catch the exception and do something else in that case.
In general, your question is like asking how you would use a hammer to improve the qualify of a house. Use exceptions to help you implement particular behaviors. Don't look for places to use exceptions.
I think it's simply a matter of preferences, but from my experiences, I'd encourage you to use them as much as possible.
In application we currently develop at work (using Zend Framework if it matters), we use one single try..catch block to catch all exceptions throughout the application which are shown to user as, for example, error 500s and exception is logged with more information to database. I, personally, love this approach in case of PHP application as exceptions are extendable and you can basically write whatever functionality you need.
I predominantly use Try/Catch around database calls...especially inputs, updates and deletes etc.
I sometimes use it around complex data processing with arrays and loops using dynamic data and arrays where there is a chance something might go wrong, ie: missing array elements or something (I normally check for stuff like that though).
I also use them around operations over which I don't have complete control such as importing data from an external or foreign data source where there could be problems with the data or accessing the source file.
I think what is meant by "Unexpected Errors" is where you can't prevent problems through good programming practices such as checking if a file exists before "including" it, Some problems you CAN anticipate so use good practices to prevent them. Don't just leave them to chance by wrapping them in a try/catch.
Use good programming practices instead as you should do everywhere. Don't use try/catch as a lazy shortcut for everything, everywhere. That's major overkill.
I agree with #scriptocalypse. In fact I only use try/catch blocks in PHP in 2 kind of situations.
If it's possible that some external (not inside my code) issues or DB errors may take place:
Getting data from another source (eg. curl)
Getting data from files
DB-Exceptions
If I work inside another system, like a CMS or similar and I want to override a certain behavior. For example I don't want an Exception being thrown but the exceptions message being returned to the view.
You cant put try catch blocks everywhere.
However during application testing, exceptions generated should alert you to places where you need try catches. This is one reason why you should run thorough testing of you application/code.
If you see a place where you think you need it, i would put one in.
EDIT: ok you CAN put them everywhere, but you need some sense as to where to put them in your code.
I normally put Try and Catch around areas in the code that have external forces acting on it that I have no control over. For example, Opening and reading external files.. you have no control that at some point in the reading of the file, the file becomes corrupted or something else happens that you can not control like the file server dc's or something

Would I want to throw an exception or an error in this PHP script?

I have a PHP script that runs database queries. Now, if a query fails, should I trigger an error or throw an exception? I noticed that if I do the latter, the script execution will stop after facing the exception.
My code is as follows:
if (!$this->connection[0]->query($this->query))
throw new Exception($this->connection[0]->error);
What are the pros and cons of using exceptions for this kind of cases (failed queries)?
What are the pros and cons of using exceptions for this kind of cases (failed queries)?
Simply:
Pros: your application can handle the failed query gracefully, log it if need be, and move on.
Cons: performance.
That said, I think you may be focusing on the wrong question. You should be handling exceptions whenever they might happen, but they should happen very, very rarely. If your query has a reasonable chance of failing, then the query itself should be your focus rather than any error-handling mechanism.
By this I mean improving the validation of any input to your query that could cause it to choke, and not the speed of the query as a means to offset any performance hit due to error handling. In other words, find out what would make your query fail and ensure that such a state is not achieved.
Consider this analogy: if you're heading out onto the lake in a potentially leaky boat (your query), you shouldn't be worrying so much about wearing a wetsuit (error handling) as you should be about making sure the boat is watertight.
depends on your general error handling strategy and the queries passed to this function. Throwing Exceptions itself is a very good idea, IMHO, if they are caught somewhere and processed.
I think it depends on how bad the situation is if the query fails. If it is critical that the query execute properly, then definitely go with the exception.
Whichever you decide, make sure that you handle the error/exception gracefully. (try..catch, etc).
You should also take a look at this stackoverflow question.
If this is for an external website, I tend to handle errors in detail in development stage. Once the site is ready to go live, I try not to give too much detail to the end user about errors, especially database details for security reasons.
This isn't some set in stone answer, but keep security in mind when reporting and handling errors on external sites. Just a note as this might not be an external website.

Categories