drew.d.lenhart

programming, software, technology, anything on my mind...

I Made a PHP Task Scheduler!

2016/08/01

This is an experiment in creating a Job/Task Scheduler / Queue system in PHP and a little bit of Python! I'll be clear, I re-invented the wheel on this one. I did this project to help me think differently about creating applications as well as picking up a few new tricks. I started this project with the intent of getting into command line PHP, but morphed into creating a Task Scheduler ( kind of like creating a replacement for Windows Task Scheduler ). There are really good frameworks such as Laravel that has it's own Task/Queue system built in, and Symphony that can build good CLI.

I didn't build a full solution here. I only built out a few use cases such as being able to auto execute jobs/tasks that are scheduled to run within a 1 minute to 60 minute window (intervals). I didn't build out the ability to run jobs/tasks daily/monthly/yearly, but may add this at a later time.

The dashboard interface, which is built on Slim 3, you can see a list of Jobs, as well as see whats in the Queue. You can also hold/release jobs, add jobs to the queue for execution, and the usual CRUD.


This is experiment, don't use this code on your production system unless there is some form of authentication!

Notes

This project uses the following:

-PHP 5.5.12 +
-PHP PDO Extension
-Composer
-Python 3.5.2 +
-Slim 3 + dependencies
-SQLite


Command Line

The interesting thing about PHP is the ability to execute scripts via command line. Take this small script for example (lets call it example.php):


<?php
echo "Hi, welcome to the command line\n";


To run, open a command prompt and type:

php example.php
**Note, instead of using "php" you may need to specify the path to your php executable. e.g. c:\wamp\bin\php.5.5.2\php.exe path\to\example.php. It's helpfull to have PHP listed in the environment variables. For the sake of this tinker project, I created this system on a Windows box.

Running the above script should output "Hi, welcome to the command line" in the console!

Going off the ability to do command line, I created three major "commands" as parameters in my script (stphpschedule.php):

  1. check - checks the JOBS list table and determines if it's time to run, then insert into Queue
  2. execute - executes any job in the QUEUE table.
  3. builddb - builds SQLite database & mock jobs.

Executing the command: php stphpschedule.php check runs the "check" function. First, it will check a jobs interval and last run time. If the conditions are right, it then inserts a new entry into the QUEUE table. In the QUEUE table, a record will have the job name, it's path to the file, time in Queue, and hold status. The "execute" command simply verifies the file exsists, makes sure the job is not on hold ( via a flag in a field ) and then executes.



Feel free to browse the source of the "cli" directory in the project files or on github.

For the sake of this experiment, I segmented the ability to "check" and "execute" into their own cli commands. I did this as more of a way to test jobs going in and out of the queue. Originally, I set up Windows Task Scheduler to execute both commands, but I didn't like how the lowest interval on a Task Scheduler task is at 1 minute. So I created a small Python script to run these commands at a shorter interval!


Python

listen.py was created to fill in the gaps of Windows Task Scheduler executing the commands I created. This short script runs a continuous loop ( with some pauses in between, this can be adjusted by editing time.sleep(seconds) values ):


while True:
    try:
        cmd = "php -f stphpschedule.php check"
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        print ("Checking queue php script..")
        print (p)
        time.sleep(15)
        exe = "php -f stphpschedule.php execute"
        p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        time.sleep(5)
    except Exception as e:
        print (e)
        print ("Something happened!")

It's probably not the best way to implement, but I really only needed the short execution time of my commands! If you run this in Python IDLE ( press F5 ), the "check" and "execute" commands will run.

**Note, make sure you have PHP listed in your environment variables, otherwise you may need to alter this script and change "php" to the path of the php executable!

Dashboard

The dashboard was built using the Slim 3 framework. I used HelloSlim3 project as scaffolding and only consists of one page. I used MVC with this portion of the app along with Eloquent ORM! I also created various API routes for the typical create/update/delete operations.


Looking at the image above in red boxes. These boxes auto refresh every 5 seconds (This keeps content up to date constantly without having to refresh the entire window). To do so I created two additional Slim routes that query the appropriate tables, and use Ajax in a Twig view to update via javascript function setInterval(). In a separate tutorial I will break down the code to do an auto refreshing dashboard using Slim/Twig!


Conclusion

I wasn't intending on doing a full code tutorial with this tinker project. Just to merely show it off. I'm not intending to release this as a official open source project of any kind. This is just an experiment to get a working solution! Head over to the Github project and download or experiment for yourself!

Thanks for reading! --Drew

View code on Github!