Solved

AJAX Slow

Posted on 2016-07-31
15
49 Views
1 Endorsement
Last Modified: 2016-08-02
I have an AJAX Function on my website.  If an email address is entered to receive an emali, the email address is sent to the DB and it is checked to see if it is already receiving the newsletter.  If it is, the email is not entered.  If the email is not there, the email is entered and a welcome email is sent out.  A success message is sent back via JSON.  Everything works 100% no problem.  However, it takes about 10 seconds for the entire process to happen.  That seems long to me.  Is there something about my code that is causing it to go slow?

<html>
<form method="post" id="newsjoin">
<input name="email" type="text" id="email" class="newsletter-input"/>
<input name="submit" type="image" id="submit" src="img/buttons/submit.png" alt="Join Mailing List" />
</form>
</html>


<script>
                var email = $('#email');
                $(function () {
                    $("#newsjoin").on('submit', function (e) {
                        e.preventDefault();
                    });
                    $("#submit").click(function () {
                        $.ajax({
                            url: 'http://www.MYSITE/functions.php',
                            data: $("#newsjoin").serialize(),
                            method: 'POST',
                            success: function (d) {
                                // d will hold the json representation of $errors
                                if (d.length) {
                                    // there are errors
                                    $("#successmessage").html(function () {
                                        var successmessage = d;
                                        return successmessage;
                                    });
                                    $("#newsjoin")[0].reset();
                                }
                            }
                        });
                    });
                });
            </script>

PHP: 'http://www.MYSITE/functions.php',
<php>
error_reporting(E_ALL);
Y
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "BLAHt";
$db_user = "BLAH";
$db_word = "BLAH";

$dsn = "mysql:host=$db_host;dbname=$db_name";
try
{
    $pdo = new PDO($dsn, $db_user, $db_word);
}
catch(PDOException $exc)
{
    var_dump($exc);
    trigger_error('NO PDO Connection', E_USER_ERROR);
}

$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );


$e = $_POST['email'];
$user_id = "1";

        $sql = "SELECT subscriber_id FROM subscribers WHERE email = :email";
        $pdos = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));
        $pdos->bindParam(':email', $e, PDO::PARAM_STR);

//  START the TRY to see if the email is already in the DB
        try {

            $pdos->execute();
            $num = $pdos->rowCount();
print_r(error_get_last(),true);
            //  START if the email is available
            if ($num == 1) { // The email address is not available.
                $success = 'That email address <br /> ' . $e . ' has already been registered and is receiving our newsletter';
                        echo json_encode($success);
            } else {

                // Add the user to the database:
                $q = "INSERT INTO subscribers
                  (email, time_registered, user_id, season, status) VALUES 
                  (:email, NOW(), :user_id, 6, 1)";

                $pdos_b = $pdo->prepare($q, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL));

                $pdos_b->bindParam(':email', $e, PDO::PARAM_STR);
                $pdos_b->bindParam(':user_id', $user_id, PDO::PARAM_STR);

                //  START Run the insert query
                try {
                    $pdos_b->execute();
                    $num_b = $pdos_b->rowCount();

//  START If an email address has been successfully added to the DB
                    if ($num_b) {
                        // SEND EMAIL NOTIFICATION
                        $body = 'Dear Colleague, THE NOTE';
 
';
                        $subject = 'Site Newst';
                        $headers = 'From:  <info@MYSITE.com>';
                        if(mail($e, $subject, $body, $headers, '-f info@MYSITE.com')) {
                            echo "mail Sent.";
                        } else {
                            echo "Mail NOT sent " . print_r(error_get_last(),true);
                        }
// END EMAIL NOTIFICATION

                        $success = 'The email address ' . $e . '  has been entered into the DB.';
                        echo json_encode($success);	
                    } else { // If it did not run OK.
                        $success = '<span class="red">This email address could not be registered due to a system error. We apologize for any inconvenience.</span>';
                        echo json_encode($success);	
                    }

//  END If an email has been successfully added to the DB
                }  //  END The Insert query
                catch (PDOException $exc) {
                    var_dump($exc);
                    trigger_error($exc->getMessage(), E_USER_ERROR);
                }
            }
        }  // END THIS Is the end of the first query to see if the email was already in the DB
        catch (PDOException $exc) {
            var_dump($exc);
            trigger_error($exc->getMessage(), E_USER_ERROR);
        }

Open in new window

1
Comment
Question by:rgranlund
  • 6
  • 5
  • 3
  • +1
15 Comments
 
LVL 34

Accepted Solution

by:
gr8gonzo earned 500 total points
ID: 41736755
Use microtime(true) and the __LINE__ magic constant to log how long it takes between various sections of code. When I'm debugging code performance, I sprinkle this line all around the script:

file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);

What that line does is it write the current line number and the current timestamp (down to the microsecond level of precision) to a file called "performance.log". So if I wanted to see how long it took for PHP to perform different areas of code, I'd put that line around them like this:

file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);
$pdo = new PDO($dsn, $db_user, $db_word);
file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);

and

file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);
$pdos->execute();
file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);

and

file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);
 $pdos_b->execute();
file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);


Then you run a single test and when it finishes running, go look at the performance.log file in a text editor. You should see output like this:

11::1469997408.8966
13::1469997408.9302
...etc...

From there, look for big differences between the timestamps. The above two example lines would show that line 12 (in-between lines 11 and 13) took about 0.04 seconds to execute, which is pretty fast.  Look for anything that takes more than 1 second to execute and if necessary, move your logging lines around to narrow the range as far as you can, and you should be able to get a better idea of what areas of the code are taking the longest to run. Provide us with the output and the lines of code that took the longest, and we can provide some feedback based on that.
2
 
LVL 82

Expert Comment

by:Dave Baldwin
ID: 41736780
Do you have an index on the email address column?  If you don't then MySQL will search thru every row in the database table to find out whether it exists.
2
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41737062
If your server code is compiling and sending the welcome message as part of the AJAX call then I would make that the prime suspect.

My approach would be to add the email to a queue and have a separate process manage the queue.
1
 
LVL 34

Expert Comment

by:gr8gonzo
ID: 41737778
@julanH - Usually emailing doesn't take very long. It's often just PHP dropping it off with the mailer service on the system, which is often a matter of milliseconds. A separate queue-managed emailing process would likely only make sense for bulk mailing.
1
 
LVL 7

Author Comment

by:rgranlund
ID: 41737839
@ Dave, can you elaborate?  There is an index column yes, can you explain just a little more.
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41737895
@gr8gonzo do I place that file in the same folder as the script or in the root?
0
 
LVL 34

Expert Comment

by:gr8gonzo
ID: 41737902
Are you talking about the log file? You can place it wherever you want - it should only be there for debugging, so you would remove it (and the debugging / logging code) after you figured out the problem.
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 7

Author Comment

by:rgranlund
ID: 41737941
@gr8gonzo
So between line number 109 and 114 there is a 11 second gap.
109::1470079702.3828
113::1470079713.0241

That line in my code is this:
 file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);
                        $subject = 'Website Stuff';
                        $headers = 'From: Rock Intuit <rockintuit@MYSITE.com>';
                        if(mail($e, $subject, $body, $headers)) {
                            file_put_contents("performance.log",__LINE__."::".microtime(true),FILE_APPEND);
                            echo "Mail Sent.";
                        } else {
                            echo "Mail NOT sent " . print_r(error_get_last(),true);
                        }

Open in new window


So it is the actual mail() function?
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41737962
I added -f to the mail function and it sped up substantially.
 if(mail($e, $subject, $body, $headers, '-f info@MYSITE.com'))
0
 
LVL 34

Expert Comment

by:gr8gonzo
ID: 41737994
It could be an issue with the DNS resolution of one of the domains involved in the message. Chances are that if it timed out on the mail() line, it's because the underlying mailer service hit a problem, and it's very likely that it logged an error/warning message somewhere. You'd have to figure out what SMTP daemon you're using (sendmail, Qmail, Exim, Postfix, etc...) and then determine where it keeps its logs, and then review them.
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41738058
OK, just to let you know, I added the reply to parameter and the AJAX processed immediate, no delay.
So, reply to and the -f is what the server needed I guess.  I hope this helps someone in the future

 $headers = "From: info@MYSITE.com>\r\nReply-To: info@MYSITE.com";
                        if(mail($e, $subject, $body, $headers, '-f info@MYSITE.com')) {
                            echo "Mail Sent.";
                        } else {
                            echo "Mail NOT sent " . print_r(error_get_last(),true);
                        }

Open in new window

0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41738129
@gr8gonzo
"Usually emailing doesn't take very long"
I guess except in this case ....
0
 
LVL 34

Expert Comment

by:gr8gonzo
ID: 41738362
@julianH

No, even in this case, mail() wasn't the problem. The fact that the problem was mostly resolved with the "-f" parameter indicates that the underlying mailer service/daemon was the one timing out (-f is a parameter to that binary). Mailer daemons are also usually very lightweight. They barely process any data at all - they're often just checking and updating the headers, dumping the message into a queue, and then handling those queues.

So whenever a mailer daemon seems to freeze up, the vast majority of the time it's because of a DNS issue (this is anecdotal evidence based on my own maintenance and repair of several dozen different mail servers across different clients over the past couple of decades). It's checking domains and having trouble resolving a domain to an IP or vice-versa. Failed DNS resolutions often take a long time because a legitimate call can sometimes take a long time (e.g. a slow connection to the server itself or a slow server in the chain of one of the recursive lookups), so there's often long timeouts involved. So if there's a DNS resolution error of any kind, then the symptom will definitely appear as if the mail() command is simply freezing for 5, 10, or even 30 seconds (all depending on the daemon's configuration).

If you try to simply let the mail() command be slow and pass it off to a queue for a separate process to send, then you're not fixing the error - you're just hiding it and eventually that queue will grow to a point where it can't be processed in a timely manner and then presents a more complex problem that you would not have had otherwise.

Most mailer problems are fairly easy to fix once you find out what the problem is. It's usually just a simple configuration issue - adding some internal DNS entries, fixing a typo in a config file, freeing up a full temp partition, etc...
0
 
LVL 7

Author Comment

by:rgranlund
ID: 41738509
Would I talk to my hosting provider?  This is a bit over my head so I don't really know where to start.
0
 
LVL 51

Expert Comment

by:Julian Hansen
ID: 41738530
@gr8gonzo,

Thanks - I am aware of all the issues you have raised - however, it does not change the fact that the question was why the AJAX call was slow and my response was - check the mail part of it - that is where it is most likely to be - which it was. Weather or not it was actually the process that sends out the email or the bit that resolves a domain name is not really relevant. I have had many issues where mail servers have been temporarily unavailable which has delayed a the process of sending email. Under normal conditions - yes it is very quick but when it fails it hangs up your script. Therefore, I put my mail requests into a separate process - this is good practice in general as it separates the moving parts that can interfere with each other. It is not always prudent to do this but as mentioned in my post it is what I do - it is an option.

@rgranlund - are you still experiencing issues or has the problem resolved?
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
Introduction If you're like most people, you have occasionally made a typographical error when you're entering information into an online form.  And to your consternation, the browser remembers the error, and offers to autocomplete your future entr…
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now