I have a website in PHP and users can schedule message to be sent. I can sent message with command similar to this one:
php sendMsg.php 249
where number is ID of the message
Many people suggested to use cron jobs, but since I don't want to run this in interval cron is no option(only once - for example after 3 hours).
My idea was as follows:
$seconds = $hours*60*60;
exec('sleep '.$seconds.'; php sendMsg.php 249');
But this wont work because it will block php for further executing. What is the simplest way to achieve this?
You said you don't want to use a cron job because you only want the message sent once, but this is mis-understanding the way that a cron job would be written for this kind of task
Consider a situation where you have many users creating many messages to be sent at various given points in time.
You don't want to have a PHP program sitting running on your server all that time for each of those messages; it would be wasteful of server resources, even if they were all just sleep()ing for the duration.
Instead, one would use a cron job to run a short-lived PHP program once every minute (or whatever interval suits you).
Your message creation program would not be written to acually send the message; instead it would insert it into a database, along with the time it needs to be sent.
Meanwhile, the cronjob PHP program would scan this database every minute to see if there are any messages that are due to send but have not yet been sent. It would then send those messages and mark them as 'sent' on the DB.
This is the standard way to write this kind of thing, so it's not surprising that people are recommending it to you.
Doing it this way means that you never have a program running on your system for longer than necessary. Both PHP programs do their job quickly and exit, meaning that no-one is kept waiting for them.
It also makes it much more robust. Imagine if your server had to be rebooted. If you had a bunch of PHP programs running for hours waiting for their moment to send their message, they'd all be lost. On the other hand, if they had saved their message to a DB, the cron job would find them and send them correctly once the server was restarted.
Put the schedule in a database. Run a cronjob every minute or so, check the database if a message should be sent within this minute, and send it.
Is there a reason you don't want to use a cron job? That would be the simplest and most efficient way of sending the messages.
I would think that a cronjob ist still the right way
Create a table where the to be send messages are stored, with a timestamp when to be send and a flag for isSend
Create a cronjob - start php skript every 1 minute , which sends the messages with timestamp < current time and isSend = false
Ignore suggestions of cron, if you want to simply wait a period of time then use the at scheduler:
$hours = 2;
$command = sprintf('echo "php sendMsg.php 249" | at now + %d hours', $hours);
exec($command);
Related
Trying to make a dice-roll function in my telegram bot.
How it works right now:
When a user sends "roll" bot replies with sendDice method and sends another message with result like "you rolled 5, you won and blah-blah .."
> how it looks <
The problem is — the second message should not appear instantly, ideally after dice-roll animation is finished.
My first and obvious try on that was to add "sleep(3)" before sending the second message, and it worked fine, until I realized it completely delays the execution of my script for those 3 seconds. (if two users rolled at the same time, one of the users has to wait until another guy's roll will be finished). So it's not cool
What can I use? :c
The easiest option is to add the "task" to the "queue". The queue can be a table in the database with timestamps and chat id, when and to whom to send a message. Start another process, for example, which is started by cron, and it works for one minute. During that minute, he goes to the database and checks to see if there is something that needs to be sent now.
Crontab config
Open crontab
sudo crontab -e
Add next string
* * * * * php /path/to/cron.php >> /path/to/log/file/for/debug.log 2>&1
Cron run your script every 1 minute.
Cron.php "live" 60 second
cron.php:
$now = time();
$expectedTime = $now + 60;
while (true) {
Worker::run();
if ($expectedTime < time()) {
die(0);
}
}
Where Worker::run() your method, which get records from db, check timestamp and send message
From Wikipedia:
In computing, [..] fork is an operation whereby a process creates a
copy of itself.
When your PHP script runs, you can create multiple processes that interact with each other. Those processes run concurrently and asynchronous. This way you can have one process waiting to send the message, while the rest of the script continues to run.
Instead of starting another process, you could also start another thread. The technical difference between the two is explained here:
Forking vs Threading
PHP offers Process Control Extensions for both forking and threading. You might want to check out the example in the PHP documentation for pcntl_fork().
Depending on your needs, you might want to use a framework designed to handle concurrency throughout your application. If that is the case, I would recommend amphp.
I'm new to this cronjobs and I want few emails (2k to 3k mails to be more precise) to be sent at specific time and date which are in the database table.Currently to achieve this, I'm calling my mail function file(sendmail.php) for every minute using cron job and comparing the current time and the time which comes from the db table, if true the mail will be sent.By doing this I'm afraid there will be some effect on the performance.
Can we schedule cronjob right after the insert query in the php script. So that I can pass those time and date variables to it?
Does calling the file for every minute in the cron job is a good practice? Will the performance get effected because my application will be used by 25 users at a time?
Although by calling the file for every minute achieves my task, but still want to know if there are any better ways.
Thank you in advance.
for every minute using cron
If you're firing off cron jobs every minute then you're doing some thing wrong. There are problems with jitter, and concurrency.
comparing the current time and the time which comes from the db table
Does that mean you are doing the tie check outside of the DBMS? That would be very silly.
Can we schedule cronjob right after the insert query in the php script
Yes, although you'd need to use sudo to create privilege separation. However you having (potentially) thousands of cron jobs is a very bad idea.
While there is a lot missing from your problem statement, based on what you have said, I'd suggest having a cron job running once every (say) 15 minutes, polling the database for the emails to be sent in that time window - with the time comparison and concurrency locking done in the database.
I have to send bulk emails to the users. I think of having an endless loop in a cron job, where I want to fetch a few dozens or hundreds users and send emails one by one - updating the the table, that the email was sent. And also I should put some sleep interval, as soon as each packet of dozen(or hundred) users received the email. Basically it looks like
while(1 != 0) {
$notifications = // fetch notifications, where email is not sent
foreach($notifications as $notification) {
// 1) send email
// 2) update table - email was sent
}
sleep(5);
}
Now, is this all right to use, or it is considered a bad practice ?
I know, I can also use multiple crons, lets say every one minute, but to prevent overlapping when using lock file, as soon as the cron starts and the lock file exists(so another cron is still running) it should either
a) wait for some time to the first cron to finish, to start,
or
b) just return empty, allowing the next cron to do the job ASA the ongoing one is done.
The problem with a) is that, what if the crons take lot more time than expected, then after some time I will have bunch of crons in a "waiting" state. About the b) case, what if immediately after the second cron is done(returning empty), the first cron ends, so I will have a gap of ~ one minute, and I need to send emails to users as soon as possible.
also, qsn 2, what is better in performance wise, one cron in loop vs multiple crons?
Thanks
What you are describing a daemon, not a cron task.
There are lots of daemons that run continuously, so no, it's not a bad practice to do that.
If you want the daemon automatically restarted if it crashes, you could have a watchdog task, which continuously checks that the daemon is running, and starts a daemon process if one isn't running.
Another alternative (as you describe) is to have crontask that occasionally attempts to start the daemon; the startup should detect whether the daemon process is already running. If it's already running, leave it be, and just exit. If it's not running, then start another one (in the background, as a detached process. Either way, the crontask completes quickly.
(And it doesn't matter one whit whether the daemon connects to MySQL.)
Personally, I dislike endless loops. I prefer a cron job running every 5 minutes for example.
And you can optimize your script for send max emails quantity in cron job time.
You need to estimate how many emails you will send per minute. I'll assume 1 email per second.
So my idea is:
Query for 290 notifications [10 seconds delay to get and update notifications] and mark them as "sending" status (to prevent next cron dont pick them).
Send emails and save result in array (for later update).
When finished, update notifications status (sent or error).
Just my 2 cents.
I am working with an php application where i need to check a database of users for whom has birthday today.
This i do through a cron job.
Now, when i get the users with birthday, i need to send them a SMS.
The SMS has an individual time associated which determins when the SMS should be send.
Lets say John and Peter has birthday today. Peter works from 01-09 so he should get the SMS at 01 and Peter works from 08-16 so he should get his SMS at 08.
I was thinking about dynamically creating the same amount of cron jbos which equals the people who has birthday on a given date. Those cron jobs would then send the SMS to the appropiate people this one time and thats it.
My question is, is there a smarter way to do this?
Secondly, if the cron job generation idea is good enough, is there a way to remove individual old cron jobs so i dont clug up the cron job list with old jobs which will never be run again?
Thanks in advance.
If you would like to send messages to each person at a specific time using cronjobs then you would have to create a cronjob for each person. Very bad idea in my eyes as you could end up with over 1000 cronjobs!
You would be much better with a system that runs a cronjob every 5 minutes or so (however often you want), and this cronjob executes a PHP script to determine if there are any messages to send out at that time, or between now and the last cronjob.
Whilst this may mean your users could get their message up to 5 minutes late, it is unlikely because nobody I know starts work at 8:02, and therefore, if the cronjob is at 8:00, 8:05, 8:10 etc, you will almost always get the message sent right on time!
If you're worried about creating too many cron jobs (not sure how many would be a problem on your system), then why not create just one cron job at the OS level? Then you can call your program every 10 minutes or so, and it can check if there are new people that need to be sent an SMS.
I'm aware of cron jobs to execute commands at a certain time, but what if that time is not constant? For instance, suppose a user asks for a reminder email exactly 1hr after signing up for something, is there an easy way to go about doing this?
Timing is critical. I am actually trying to create AI that will essentially act on its own but only at variable points during the day. Any help would be appreciated!
You can use at to schedule jobs for specific times. cron is for repeating jobs, at is for one-shot/oddball interval ones. Both have a resolution of 1 minute, though, so you can't specify a start period with seconds granularity.
The command's available on both Unix/Linux and Windows.
Here a workable flow:
user Requests email in 1 hour
You insert into the a table action (action_id, time)
On the PHP server create a cron job to check the action in the action table every minute, then do the action that need to be done at that time
That is a simple example from the request. It might get a bit more complex then that.
EDIT : this suggestion might be good only if you need to be very precise with the time management!
if you dont wanna use the cron triggers and you are not comfortable with them here are two php scheduling libraries..
1) http://www.php.brickhost.com/
2) http://www.phpjobscheduler.co.uk/
Try them if you like: