Are wordpress cron jobs executed sequentially or in parallel? - php

I am trying to limit the number of emails sent from my website to cope with the hosting service email limitations.
I am using cron jobs and an indicator of piling the emails in the database to check if the number of emails sent is approaching the limit of max emails sent.
The way I do that, is by directly executing the scheduled process then make it 'sleep' for a certain period of time (according to its position in the queue) and then send the email and log in the database.
To explain further the reason why I am using scheduled tasks and 'sleep', consider the scenario below:
A user tries to register to my website and expects an email to be sent to him/her shortly. Thus, if the emails/minute quota is exceeded, I need to send a different message: "Our server is busy, please permit 'x' minutes to perform the required task".
The requests to send email are all done through AJAX. Using 'sleep' within the process itself is not an option because the user will have to wait the x minutes until the 'busy message' is echo'd.
I tried with ob_flush, flush...etc. combinations to echo the message then the server works out everything in the background, but that never worked. The AJAX call was always waiting for the script to end to echo the result.
I need multi-threading in the single-threaded PHP language! As a workaround I used cron jobs, where each piled email is scheduled to be executed at time() (i.e. directly fire the scheduled job) which is hooked to the same function that sends emails. Using a flag, the function knows that the request is a piled email and makes it 'sleep' until the time required for the email quota reset.
The problem: If 5 people registered at almost the same time (while we still have an email pile), then we have 5 cron jobs that should all be executed at the same time and then sleep for a while (the sleep time can differ if the number of emails in the pile are already greater than the email quota), then emails are sent. However, when I check the logs in the database, I find that the scheduled jobs are executed sequentially and not in parallel. Sometimes it happens a cron job is fired before the other ends, but they don't fire at the same time.
I know that wordpress cron jobs are not really cron jobs and are fired once somebody visits the website (and I make sure I refresh the pages after the registration requests are sent to fire all of the scheduled tasks), but they seem to be the only option for me since my hosting server doesn't allow access to the server neither allows scheduling cron jobs.
Here is part of the code that executes the above:
//Test example to pile up emails, where quota is set to 2 emails every 30 seconds
$Emails_Threshold = 2;
$Threshold_Duration = 0.5*60;
//Get email indicator info
$Email_Info = $wpdb->get_row(
"SELECT *
FROM PileEmails
WHERE priority = -1
AND Status='New';"
,ARRAY_A);
if ($sleep ==0 && $Queue_Info_id==0){ //Not a scheduled event
//Check if there are queued emails
$Queue_exist = $wpdb->get_row (
$wpdb->prepare("
SELECT Status
FROM PileEmails
WHERE Status='Queued';"
,$mail_priority)
,ARRAY_A);
if (!empty($Queue_exist) || ($Email_Info['last_email_time'] > (time()-$Threshold_Duration))){
if ($Email_Info['count_emails']>=$Emails_Threshold){
//Code to Pile up
}
}else{
//Reset email counter
}
}else{
$wpdb->insert( "PileEmails",$Sleep_Info,$format);
sleep(10); //10 seconds here just as an example
}
//Code to send emails
Here is what I get logged into the database when I try to send 10 emails after exceeding the quota.
Notice that the time stamp has 10 seconds difference between each log and the following one although they should all be fired at the same time and each sleeps for 10 seconds then all send emails in parallel.
So my question is: Why does wordpress cron fire the scheduled jobs sequentially and not in parallel? and how to overcome this problem?
Any help is much appreciated.

As mentioned, installing a cron plugin will help to manage your crons.
To answer your question, Wordpress uses a "cron lock" defined('DOING_CRON') and sets a transient $lock = get_transient('doing_cron') when the spawn_cron method is invoked.
So, if you have a look at wp-includes/cron.php you'll see Wordpress crons do not run concurrently by default and will not run more than once every 60 seconds.
// don't run if another process is currently running it or more than once every 60 sec.
if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
return;

If you can only send one or two emails at a time this is going to be tricky to solve. An easier way to solve this would probably be to have WordPress use an SMTP email server that allows the frequency of emails you need to send. Just adding a new email account on your current hosting provider might suffice. If you do not know how to set that up manually there are plugins that will do that for you.

As php runs from top to bottom so when you schedule a event using wordpress schedule event function, as below :
if (! wp_next_scheduled ( 'my_hourly_event' )) {
wp_schedule_event(time(), 'hourly', 'my_hourly_event');
}
add_action('my_hourly_event', 'do_this_hourly');
function do_this_hourly() {
// do something every hour
}
This function do_this_hourly() will run as per the schedule , but the code which you will write inside that function will run one by one only.
Let us take example of email sending to 5 persons, so the email will be sent to them one by one in a loop.
The time-stamp is entered by the insert query which you are using, there is no connection between the timestamp and the mail sent time, this timestamp you have created for your own logs , so that you can check.
There would be some difference for sure i:e 10 seconds, it can also be less or greater, depending on the time which server is taking to send email and process the insert query.
Each query will be fired and the timestamp will be inserted according to the time at that moment (server time).

Related

Scheduling emails with cron jobs from a mysql table

I am trying to set up a system where a user enters some information in a form and an email will be constructed where the information is saved into mysql.
I am trying to figure out how to make it so the email will be sent, for example, 20 minutes after the user makes their input. (Without the user staying on the browser).
I need this delay as I need the ability for an admin to log on to a page to look at the email and possibly edit it before it sends.
Is this possible through a cron job. Am I able to set one up that automatically checks sql table for an update and then sends the email after a certain time?
Or is it possible to delay a php script with the sleep function and then send the email. Can I make the PHP script still run when user has closed site and left?
you can use mySQL to store the data sent by the user. this data will be accessed later using another script triggered by a cron Job: if you have the ability to set cron jobs in the control panel or via access to the server, go ahead, use cron tab syntax to define when the job will be triggered, this website may help you:
https://crontab-generator.org/
another approach is to use external service to trigger an event every interval, the event could be accessing the cron job script via HTTP.
if you want your email to be sent exactly after 20 mins, please add a field to your mysql table indicating the desired send date(beware of timezones).
you may also want to add a flag indicating if the email is sent, so you do not send the same email twice.
You can't (easily) have a PHP script stay alive that long.
Your best strategy, IMO, would be to have the PHP script create the email file, and notify the human.
Then you can have PHP run a shell script which uses the "at" program to schedule a task to happen in 20 minutes. At is a cousin of cron, but is better suited for this job.
That scheduled task will be to take the e-mail message, move it some place else (like a "done" directory), and pipe it through your mailer. tip: /usr/sbin/sendmail -t < myEmailFile will work on most Linux boxen.

Making Email Delivery delay

This is some type of funny question to ask here.
Well, I am using WordPress with registration. When a user signup. Wordpress send email containing user name and password to login.
I simply want that email to receive after delay of 10 minutes. Is there is something to do with server config OR with WP.
Any clues?
You would have to have multiple things to have it work, you will need to have access to cron in order to delay the job and you need to be able have enough knowledge to edit WordPress to stop the function from sending the email. If you can schedule the job to run a command with the parameters for the email in it 10 minutes later the rest should run on its own.

PHP triggering mail functions at a set time and date

I want to check the stock level every day at a certain time (say 11pm GMT) and email a list of items that are low on stock to the admin. I have managed to get the mailing function working but I am struggling to limit the checks to once a day (right now it sends an email to the admin email every time the page loads)
Your help will be much appreciated!
I think that you just need to put your script in a separate file and run once per day with a cron job
You might want to read more about cron jobs in this post How to create cron job using PHP?
In case that impossible to run a cron job, you can save last mail time in DB or file and check timeout on page load.

PHP- MySQL cronjob sending mail loop repeat

In one of my web application, I am sending daily mails to the users using a cron job function via AMAZON SES. The cronjob will run in the interval of 10 mins. The process will like
$sql-mysql_query("SELECT * FROM users WHERE send_date='2013-07-13' and alert_send=0");
while($row=mysql_fetch_array($sql)) {
// Get email id of the user and compose meggage
// Create a new Amazon Request and send the mail
// Update alert_send=1
}
If the loop contains more counts ie suppose a 500 mails, on next 10th min, an another cron job will start and start sending mails. At the end users will get the mail twice or thrice accordingly.
ie. If the loop contains 500 datas
Cron A will start at 12:00 and fetch all the 500 datas and send emails. Suppose send mails 120 with 10 mins.
Cron B will start at 12:10 and fetch data from 120 - 500. This will also send mail.
By this result, 121 th user will get mails from Cron A and Cron B.
I tried of limit the query count. But the problem is we cant predict when each loop ends. ie sometimes it will take 4,2,5,6 or 10 secs for send a mail.
Is there any way to avoid this duplicating ? Is there any way to kill the existing cronjob and start new ?
Thanks in advance
Everytime when the cronjob start you can kill the cronjob that is running
like this by the name:
pkill process-name
or like this by id:
kill 1234
Also you can take a look at this blog that use php code :
http://abhinavsingh.com/blog/2009/12/how-to-use-locks-in-php-cron-jobs-to-avoid-cron-overlaps/

start a second instance from PHP, and allow suspension with sleep, without generating the TIMEOUT error?

Everything Cut Short:
Need to execute a function after around 5 minutes after a request sent by Google Checkout's Notification Service.
Why: The History API requires the transaction to be atleast 5 min old to work.
What has been tried, suspending teh function by sleep, but it generates a TIMEOUT error at google's end.
Main Concern: The function must run, even if the user navigates away from page, reloads the page, or closes his/her browser or logout from the Site..
Tried, Google but not of much use..
Any Ideas??
This sounds like a job for cron. Here's a possible implementation outline:
When Google sends a Checkout Notification, record the notifcation details and timestamp in your database.
Setup a script to be run by cron. The script will check the database for new Checkout Notifications that are at least 5 minutes old.
The script will then access the History API for those matching records and then mark those records in the database so that they won't be accessed again the next time the cron job runs.
The cron job can be set to run at any interval you like. The lower the interval, the more quickly History API requests will be made as Checkout Notifications hit the 5 minute age. Your cron script can record the result of the History API request in your database so that your web interface can retrieve it and show it to the user.

Categories