I would have a console application acting as a service in the background, which listens for commands that can be given by your frontend application. For instance, the service might run as a cron every 1 minute, which monitors a table in the database and, if it finds an entry earmarked as being incomplete (i.e. status = 0), it executes it and sends the push notification (and afterwards may mark status as 1, or delete the entry).
I don’t send mail out locally on most of my applications - I use a 3rd party via SMTP. It hangs for about 1 second to send a single email, so if my frontend application is trying to send out a bulk message, the application hangs for a long time. To combat this, I have an email service running in the background (not on a cron, it just runs 24/7 in the background intermittently checking for emails to send, and a cron restarts it if it fails), which monitors an email table in the database. When a new entry is added to the table, the service processes it. No hang, no worries.
An approach like this also has the added benefit of being able to share the load throughout a range of resources. Services are typically useful for processes that can be quite intensive. For instance, if I had an email service that was processing 2,000 emails/minute, I might want to move that off of my web server and on to its own box. It would be accomplished by simply migrating the email service, and would have no carry over effects on to the web application itself.
What I use largely depends on what I’m trying to accomplish. For instance, If I’m just reading and writing to one table and sending emails, there’s absolutely no onus on me to use Yii (and hence PHP). If the service is aiming to do something which would benefit more from Yii’s rich feature set (i.e. use of shared resources - AR models, components, etc.), I would probably build it in Yii.
Yes, I loop and then sleep prior to the next iteration. I have a service which monitors all of my services. I can stop/start specific services (so instead of while(1) I would have something like while(SERVICE_IS_ACTIVE)), and instead of sleep(10) I would have sleep(SERVICE_DELAY)). The delay depends again on what you’re trying to achieve. If you need to send push notifications out almost instantly, a shorter delay would be more appropriate.
Each service updates when it last runs (i.e. a simple UPDATE services SET last_run = CURRENT_TIMESTAMP WHERE service_id = ‘email’). If the last_run exceeds a certain threshold, it’s failed. I also catch exceptions in my services and try to fail/restart gracefully.