Skip to content

Commit 912050e

Browse files
committed
Initial commit
0 parents  commit 912050e

27 files changed

+3014
-0
lines changed

.gitattributes

Whitespace-only changes.

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/vendor
2+
.idea
3+
composer.lock
4+
test*

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Eugene Ivanov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Simple PHP Scheduler
2+
Supports various types of tasks, task batches, customizable logging with any [PSR-3](https://www.php-fig.org/psr/psr-3/) logger or stdout/stderr, full launch log in the database (powered by Doctrine DBAL).
3+
## Installation
4+
Requires PHP version 7.2 or higher
5+
```bash
6+
$ composer require evgeek/scheduler
7+
```
8+
## Basic usage
9+
Create php file (```scheduler.php``` for example) with scheduler setup code:
10+
```php
11+
<?php
12+
13+
use Doctrine\DBAL\DriverManager;
14+
use Evgeek\Scheduler\Scheduler;
15+
use Evgeek\Scheduler\Handler\DatabaseLogging;
16+
17+
require_once __DIR__ . '/path/to/vendor/autoload.php';
18+
19+
//Create DBAL connector
20+
$uri = 'mysql://user:secret@localhost/mydb';
21+
$conn = \Doctrine\DBAL\DriverManager::getConnection(['url' => $uri]);
22+
23+
//Create new instance of the scheduler
24+
$handler = new DatabaseLogging($conn);
25+
$scheduler = new Scheduler($handler);
26+
27+
//Create, add to scheduler and setup new task
28+
$scheduler->task(function() {
29+
echo 'Hello world!';
30+
})
31+
->schedule()
32+
->every(1);
33+
34+
//Run the scheduler
35+
$scheduler->run();
36+
```
37+
And add new line to crontab to run your scheduler file every minute:
38+
```
39+
* * * * * /usr/bin/php /path/to/your/scheduler.php
40+
```
41+
## Supported task types
42+
All tasks are created using the ```$scheduler->task()``` method. The task type is recognized automatically.
43+
### Closure
44+
```php
45+
$scheduler->task(function() {echo 'Hello world!';});
46+
```
47+
### Bash command
48+
```php
49+
$scheduler->task('ls -la');
50+
```
51+
### Php file
52+
```php
53+
$scheduler->task('/path/to/your/file.php');
54+
```
55+
### Job interface
56+
The scheduler can work with any class that implements a simple interface ```Evgeek\Scheduler\JobInterface``` (single required method ```dispatch()``` must run the task).
57+
```php
58+
$scheduler->task(new Job());
59+
```
60+
### Bunch
61+
You can combine several tasks of different types into a batch and manage their launch in the same way as a single task.
62+
```php
63+
$scheduler->task([
64+
$scheduler->task(function() {echo 'Hello world!';}),
65+
$scheduler->task('ls -la'),
66+
$scheduler->task('/path/to/your/file.php'),
67+
$scheduler->task(new Job())
68+
]);
69+
```
70+
## Setting up a task
71+
After creating a task using the ```task()``` method, you can add it to the scheduler using the ```schedule()``` method. After that, various methods of setting up the task launch become available.
72+
### Work mode methods
73+
* **_repetitive_** - using the ```every()``` (every X minutes) or ```delay()``` (X minutes after previous launch finished) methods.
74+
* **_interval_** - using the ```addInterval()```, ```daysOfWeek()```, ```daysOfMonth()```, ```months()``` and ```years()``` methods. If interval mode is used with repetitive mode, the task will be launched repetitive at the specified intervals, otherwise the task will be launched once per interval.
75+
#### Examples
76+
* Every hour
77+
```php
78+
$scheduler->task(new Job())
79+
->schedule()
80+
->every(60);
81+
```
82+
* Every night all night with 5 minutes delay
83+
```php
84+
$scheduler->task(new Job())
85+
->schedule()
86+
->addInterval('00:00', '06:00')
87+
->delay(5);
88+
```
89+
* Every Sunday, once from 03:00 to 04:00 and once from 15:00 to 16:00
90+
```php
91+
$scheduler->task(new Job())
92+
->schedule()
93+
->addInterval('03:00', '04:00')
94+
->addInterval('15:00', '16:00')
95+
->daysOfWeek([7]);
96+
```
97+
* Once on 1st January and December and every Monday and Wednesday in January and December
98+
```php
99+
$scheduler->task(new Job())
100+
->schedule()
101+
->daysOfWeek(['Mon', 'wednesday'])
102+
->daysOfMonth([1])
103+
->months(['Jan'])
104+
->months(['Dec']);
105+
```
106+
* Every minute January 1, 2022
107+
```php
108+
$scheduler->task(new Job())
109+
->schedule()
110+
->every(1)
111+
->daysOfMonth([1])
112+
->months(['Jan'])
113+
->years([2022]);
114+
```
115+
### Setup methods
116+
```php
117+
$scheduler->task(new Job())
118+
->schedule()
119+
->every(1)
120+
->name('Job')
121+
->description('A very useful task')
122+
->tries(3);
123+
```
124+
* ```name()``` - task name for the log.
125+
* ```description()``` - task description for the log.
126+
* ```preventOverlapping()``` (default ```false```) - if true, the task cannot start if another instance of this task is currently running.
127+
* ```lockResetTimeout()``` (default ```360```) - how long (in minutes) the task lock should be recognized as frozen and reset.
128+
* ```tries()``` (default ```1```) - how many attempts to complete the task should be made in case of an error.
129+
* ```tryDelay()``` (default ```0```) - how long (in minutes) to wait before retrying the failed task.
130+
### Helper methods
131+
* ```getSettings()``` - returns array with task settings.
132+
* ```logDebug()``` - send a message to the debug channel immediately.
133+
* ```logError()``` - send a message to the error channel immediately.
134+
## Scheduler setup
135+
You can configure scheduler with handler object implements ```\Evgeek\Scheduler\Handler\LockHandlerInterface``` and config object ```Evgeek\Scheduler\Config```. Example:
136+
```php
137+
//Creates and setup handler
138+
$uri = 'mysql://user:secret@localhost/mydb';
139+
$conn = \Doctrine\DBAL\DriverManager::getConnection(['url' => $uri]);
140+
$handler = new \Evgeek\Scheduler\Handler\DatabaseLogging(
141+
$conn,
142+
'scheduler_tasks',
143+
'scheduler_launches'
144+
);
145+
146+
//Creates and setup config
147+
$config = new \Evgeek\Scheduler\Config();
148+
$config
149+
->setDebugLogging(true)
150+
->setDefaultTries(3);
151+
152+
//Creates scheduler with handler and (optional) config
153+
$scheduler = new Scheduler($handler, $config);
154+
```
155+
### Handlers
156+
Lock handler, implements ```\Evgeek\Scheduler\Handler\LockHandlerInterface```. So far, only one is available.
157+
* ```\Evgeek\Scheduler\Handler\DatabaseLogging```\
158+
Stores locks in the database with tasks information in one table and a full launch log in another. Needs configured [Doctrine DBAL](https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/introduction.html) object as first parameter of constructor. You can pass custom task table name to the second optional parameter, and table name to the third.
159+
### Config
160+
Allows you to configure other scheduling options. You can do this using ```Config``` constructor parameters or using ```$config``` methods:
161+
#### Logger
162+
The scheduler has two log channels: ```debug``` for getting detailed launch information and ```error``` for task errors. Methods for configure:
163+
* ```setDebugLogging()``` (default ```false```) - enable/disable ```debug``` channel.
164+
* ```setErrorLogging()``` (default ```true```) - enable/disable ```error``` channel.
165+
* ```setLogger()``` (default ```null```) - set [PSR-3](https://www.php-fig.org/psr/psr-3/) compatible logger. If passed ```null```, log will be sent to ```STDOUT```/```STDERR```.
166+
* ```setDebugLogLevel()``` (default ```null```) - sets custom log level for the PSR-3 logger for ```debug``` messages. By default, this is ```debug```.
167+
* ```setDErrorLogLevel()``` (default ```null```) - sets custom log level for the PSR-3 logger for ```error``` messages. By default, this is ```error```.
168+
* ```setLogUncaughtErrors()``` (default ```false```) - registers shutdown function for log uncaught exceptions such as PHP fatal errors or incorrect task settings.
169+
* ```setLogMessageFormat()``` (default ```"[{{task_id}}. {{TASK_TYPE}} '{{task_name}}']: {{message}}"```) - formatting template for task logger. Available variables:
170+
* ```{{task_id}}```
171+
* ```{{task_type}}```
172+
* ```{{TASK_TYPE}}```
173+
* ```{{task_name}}```
174+
* ```{{TASK_NAME}}```
175+
* ```{{message}}```
176+
* ```{{MESSAGE}}```
177+
* ```{{task_description}}```
178+
* ```{{TASK_DESCRIPTION}}```
179+
180+
Lowercase for regular case, uppercase - for forced uppercase. Log message example with default formatting:
181+
```php
182+
/* ... */
183+
$config->setDebugLogging(true);
184+
/* ... */
185+
$scheduler->task('ls -la')
186+
->schedule()
187+
->delay(0)
188+
->tries(3);
189+
```
190+
```
191+
[0. COMMAND 'ls -la']: Checking if it's time to start
192+
[0. COMMAND 'ls -la']: Launched (try 1/3)
193+
[0. COMMAND 'ls -la']: Completed in 00s
194+
```
195+
* ```setCommandOutput()``` (default ```false```) - enable/disable shell output for `bash command` tasks.
196+
#### Default task options
197+
Some options for setting default task options. The parameters specified in the task overwrite the default values.
198+
* ```setDefaultPreventOverlapping()``` (default ```false```) - if true, the task cannot start if another instance of this task is currently running.
199+
* ```setDefaultLockResetTimeout()``` (default ```360```) - how long (in minutes) the task lock should be recognized as frozen and reset.
200+
* ```setDefaultTries()``` (default ```1```) - how many attempts to complete the task should be made in case of an error.
201+
* ```setDefaultTryDelay()``` (default ```0```) - how long (in minutes) to wait before retrying the failed task.
202+
#### Others
203+
* ```setMinimumIntervalLength()``` (default ```30```) - Minimum interval size in minutes (for task method ```addInterval()```). Currently, tasks are started sequentially and synchronously, so the scheduler cannot guarantee the exact time when the task will start. Because of this, I had to limit the minimum size of the interval to make sure that the task will not be missed because the interval is too small. This is not a good decision. In future updates, task launching will be implemented asynchronously, and the interval limitation will be removed.
204+
## Future plans
205+
* Asynchronous task launch.
206+
* Tests.
207+
* More lock handlers, first - file lock handler as default behavior.
208+
* More scheduling options, including launch at exact time.
209+
* Managing the scheduler using console commands - list of task, force start all or specific task etc.

composer.json

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "evgeek/scheduler",
3+
"description": "Simple scheduler",
4+
"keywords": ["scheduler", "cron"],
5+
"homepage": "https://github.com/evgeek/scheduler",
6+
"type": "library",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Eugene Ivanov",
11+
"email": "evgeeek@gmail.com",
12+
"homepage": "https://github.com/evgeek"
13+
}
14+
],
15+
"require": {
16+
"php": ">=7.2",
17+
"psr/log": "^1.1",
18+
"nesbot/carbon": "2.54.*",
19+
"doctrine/dbal": "3.1.*",
20+
"ext-json": "*"
21+
},
22+
"require-dev": {
23+
"roave/security-advisories": "dev-latest"
24+
},
25+
"config": {
26+
"optimize-autoloader": true,
27+
"preferred-install": "dist",
28+
"sort-packages": true
29+
},
30+
"autoload": {
31+
"psr-4": {
32+
"Evgeek\\Scheduler\\": "src"
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)