├── QueueController.php
├── views
└── default
│ ├── create.php
│ ├── update.php
│ ├── stat.php
│ ├── view.php
│ ├── _search.php
│ ├── _form.php
│ ├── report.php
│ └── index.php
├── composer.json
├── models
├── generated
│ ├── QueueManagerQuery.php
│ └── QueueManager.php
├── QueueManager.php
└── search
│ └── QueueManagerSearch.php
├── Job.php
├── assets
└── QueueManagerAsset.php
├── LICENSE.md
├── messages
├── config.php
├── en
│ └── queuemanager.php
└── ru
│ └── queuemanager.php
├── migrations
└── m171020_204247_init.php
├── README.md
├── QueueManager.php
├── behaviors
└── QueueManagerBehavior.php
├── helpers
└── QueueManagerHelper.php
├── js
└── queuemanager.js
└── controllers
└── DefaultController.php
/QueueController.php:
--------------------------------------------------------------------------------
1 | modify('-7 days');
15 |
16 | \ignatenkovnikita\queuemanager\models\QueueManager::deleteAll(['<','created_at', $dateTime->getTimestamp()]);
17 |
18 | }
19 |
20 |
21 | }
--------------------------------------------------------------------------------
/views/default/create.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('queuemanager', 'Create {modelClass}', [
10 | 'modelClass' => 'Queue Manager',
11 | ]);
12 | $this->params['breadcrumbs'][] = ['label' => Yii::t('queuemanager', 'Queue Managers'), 'url' => ['index']];
13 | $this->params['breadcrumbs'][] = $this->title;
14 | ?>
15 |
16 |
17 | render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ignatenkovnikita/yii2-queuemanager",
3 | "description": "Yii2 Queue Manager",
4 | "type": "yii2-extension",
5 | "keywords": ["yii2","extension","queue","manager"],
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Ignatenkov Nikita",
10 | "email": "ignatenkov.n@gmail.com"
11 | }
12 | ],
13 | "require": {
14 | "yiisoft/yii2": "~2.0.0",
15 | "yiisoft/yii2-jui": "~2.0.0",
16 | "2amigos/yii2-chartjs-widget": "~2.0"
17 | },
18 | "autoload": {
19 | "psr-4": {
20 | "ignatenkovnikita\\queuemanager\\": ""
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/views/default/update.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('queuemanager', 'Update {modelClass}: ', [
9 | 'modelClass' => 'Queue Manager',
10 | ]) . ' ' . $model->name;
11 | $this->params['breadcrumbs'][] = ['label' => Yii::t('queuemanager', 'Queue Managers'), 'url' => ['index']];
12 | $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];
13 | $this->params['breadcrumbs'][] = Yii::t('queuemanager', 'Update');
14 | ?>
15 |
16 |
17 | render('_form', [
18 | 'model' => $model,
19 | ]) ?>
20 |
21 |
22 |
--------------------------------------------------------------------------------
/models/generated/QueueManagerQuery.php:
--------------------------------------------------------------------------------
1 | andWhere('[[status]]=1');
15 | }*/
16 |
17 | /**
18 | * @inheritdoc
19 | * @return QueueManager[]|array
20 | */
21 | public function all($db = null)
22 | {
23 | return parent::all($db);
24 | }
25 |
26 | /**
27 | * @inheritdoc
28 | * @return QueueManager|array|null
29 | */
30 | public function one($db = null)
31 | {
32 | return parent::one($db);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Job.php:
--------------------------------------------------------------------------------
1 |
6 | * @file Job.php
7 | * @author ignatenkovnikita
8 | * @date $date$
9 | */
10 |
11 | /**
12 | * Created by PhpStorm.
13 | * User: ignatenkovnikita
14 | * Web Site: http://IgnatenkovNikita.ru
15 | */
16 |
17 | namespace ignatenkovnikita\queuemanager;
18 |
19 |
20 | use yii\base\BaseObject;
21 | use yii\base\InvalidConfigException;
22 |
23 | class Job extends BaseObject
24 | {
25 | public $name;
26 |
27 | public function init()
28 | {
29 | if (empty($this->name)) {
30 | throw new InvalidConfigException('Property name not empty, please set value');
31 | }
32 | parent::init(); // TODO: Change the autogenerated stub
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/views/default/stat.php:
--------------------------------------------------------------------------------
1 |
6 | * @file stat.php
7 | * @author ignatenkovnikita
8 | * @date $date$
9 | */
10 |
11 | use yii\helpers\Html;
12 | use yii\widgets\DetailView;
13 |
14 | /* @var $this yii\web\View */
15 | /* @var $model ignatenkovnikita\queuemanager\models\QueueManager */
16 |
17 | $this->title = 'Statistic in realtime';
18 | $this->params['breadcrumbs'][] = ['label' => Yii::t('queuemanager', 'Queue Managers'), 'url' => ['index']];
19 | $this->params['breadcrumbs'][] = $this->title;
20 | \ignatenkovnikita\queuemanager\assets\QueueManagerAsset::register($this);
21 | ?>
22 |
23 |
24 |
25 |
26 |
27 | Активные workers
28 |
29 |
30 |
--------------------------------------------------------------------------------
/assets/QueueManagerAsset.php:
--------------------------------------------------------------------------------
1 |
8 | * @file QueueManagerAsset.php
9 | * @author ignatenkovnikita
10 | * @date $date$
11 | */
12 |
13 | /**
14 | * Created by PhpStorm.
15 | * User: ignatenkovnikita
16 | * Web Site: http://IgnatenkovNikita.ru
17 | */
18 | class QueueManagerAsset extends \yii\web\AssetBundle
19 | {
20 | // public $depends = [
21 | // 'yii\web\JqueryAsset',
22 | // 'yii\bootstrap\BootstrapAsset',
23 | // 'trntv\filekit\widget\BlueimpFileuploadAsset'
24 | // ];
25 |
26 | public function init()
27 | {
28 | $this->sourcePath = __DIR__ . "/../";
29 | // $this->css = [
30 | // YII_DEBUG ? 'css/upload-kit.css' : 'css/upload-kit.min.css'
31 | // ];
32 |
33 | $this->js = [
34 | 'js/queuemanager.js'
35 | ];
36 | parent::init();
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Nikita Ignatenkov
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.
22 |
--------------------------------------------------------------------------------
/messages/config.php:
--------------------------------------------------------------------------------
1 | null,
14 | 'interactive' => true,
15 | 'help' => null,
16 | 'sourcePath' => '@vendor/ignatenkovnikita/yii2-queuemanager',
17 | 'messagePath' => 'vendor/ignatenkovnikita/yii2-queuemanager/messages/',
18 | 'languages' => ['en', 'ru'],
19 | 'translator' => 'Yii::t',
20 | 'sort' => false,
21 | 'overwrite' => true,
22 | 'removeUnused' => false,
23 | 'markUnused' => true,
24 | 'except' => [
25 | '.svn',
26 | '.git',
27 | '.gitignore',
28 | '.gitkeep',
29 | '.hgignore',
30 | '.hgkeep',
31 | '/messages',
32 | '/BaseYii.php',
33 | ],
34 | 'only' => [
35 | '*.php',
36 | ],
37 | 'format' => 'php',
38 | 'catalog' => 'messages',
39 | 'ignoreCategories' => [],
40 | 'phpFileHeader' => '',
41 | 'phpDocBlock' => null,
42 | ];
43 |
--------------------------------------------------------------------------------
/views/default/view.php:
--------------------------------------------------------------------------------
1 | title = $model->name;
10 | $this->params['breadcrumbs'][] = ['label' => Yii::t('queuemanager', 'Queue Managers'), 'url' => ['index']];
11 | $this->params['breadcrumbs'][] = $this->title;
12 | ?>
13 |
14 |
15 |
16 | $model->id], ['class' => 'btn btn-primary']) ?>
17 | $model->id], [
18 | 'class' => 'btn btn-danger',
19 | 'data' => [
20 | 'confirm' => Yii::t('queuemanager', 'Are you sure you want to delete this item?'),
21 | 'method' => 'post',
22 | ],
23 | ]) ?>
24 |
25 |
26 | $model,
28 | 'attributes' => [
29 | 'id',
30 | 'name',
31 | 'sender',
32 | 'ttr',
33 | 'delay',
34 | 'priority',
35 | 'status',
36 | 'class',
37 | 'properties:ntext',
38 | 'data:ntext',
39 | 'result_id',
40 | 'result:ntext',
41 | 'created_at:datetime',
42 | 'updated_at:datetime',
43 | 'start_execute:datetime',
44 | 'end_execute:datetime',
45 | ],
46 | ]) ?>
47 |
48 |
49 |
--------------------------------------------------------------------------------
/migrations/m171020_204247_init.php:
--------------------------------------------------------------------------------
1 | db->driverName === 'mysql') {
13 | $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
14 | }
15 | $this->createTable(self::TABLE_NAME, [
16 | 'id' => $this->primaryKey(),
17 | 'name' => $this->string(),
18 | 'sender' => $this->string(),
19 | 'ttr' => $this->integer(),
20 | 'delay' => $this->integer(),
21 | 'priority' => $this->integer(),
22 | 'status' => $this->integer(),
23 | 'class' => $this->string(),
24 | 'properties' => $this->text(),
25 | 'data' => $this->text(),
26 | 'result_id' => $this->integer(),
27 | 'result' => $this->text(),
28 | 'created_at' => $this->bigInteger(),
29 | 'updated_at' => $this->bigInteger(),
30 | 'start_execute' => $this->bigInteger(),
31 | 'end_execute' => $this->bigInteger(),
32 | ], $tableOptions);
33 |
34 | }
35 |
36 | public function safeDown()
37 | {
38 | $this->dropTable(self::TABLE_NAME);
39 | }
40 |
41 | /*
42 | // Use up()/down() to run migration code without a transaction.
43 | public function up()
44 | {
45 |
46 | }
47 |
48 | public function down()
49 | {
50 | echo "m171020_204247_init cannot be reverted.\n";
51 |
52 | return false;
53 | }
54 | */
55 | }
56 |
--------------------------------------------------------------------------------
/messages/en/queuemanager.php:
--------------------------------------------------------------------------------
1 | '',
21 | 'Are you sure you want to delete this item?' => '',
22 | 'Class' => '',
23 | 'Create' => '',
24 | 'Create {modelClass}' => '',
25 | 'Created At' => '',
26 | 'Data' => '',
27 | 'Delay' => '',
28 | 'Delete' => '',
29 | 'End Execute' => '',
30 | 'ID' => '',
31 | 'Name' => '',
32 | 'Priority' => '',
33 | 'Properties' => '',
34 | 'Queue Managers' => '',
35 | 'Repeat' => '',
36 | 'Reset' => '',
37 | 'Result' => '',
38 | 'Result ID' => '',
39 | 'Search' => '',
40 | 'Sender' => '',
41 | 'Start Execute' => '',
42 | 'Status' => '',
43 | 'Status Done' => '',
44 | 'Status Error' => '',
45 | 'Status Reserved' => '',
46 | 'Status Waiting' => '',
47 | 'Time Execute' => '',
48 | 'Ttr' => '',
49 | 'Update' => '',
50 | 'Update {modelClass}: ' => '',
51 | 'Updated At' => '',
52 | ];
53 |
--------------------------------------------------------------------------------
/views/default/_search.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | ['index'],
15 | 'method' => 'get',
16 | ]); ?>
17 |
18 | field($model, 'id') ?>
19 |
20 | field($model, 'name') ?>
21 |
22 | field($model, 'sender') ?>
23 |
24 | field($model, 'ttr') ?>
25 |
26 | field($model, 'delay') ?>
27 |
28 | field($model, 'priority') ?>
29 |
30 | field($model, 'status') ?>
31 |
32 | field($model, 'class') ?>
33 |
34 | field($model, 'properties') ?>
35 |
36 | field($model, 'data') ?>
37 |
38 | field($model, 'result_id') ?>
39 |
40 | field($model, 'result') ?>
41 |
42 | field($model, 'created_at') ?>
43 |
44 | field($model, 'update_at') ?>
45 |
46 | field($model, 'start_execute') ?>
47 |
48 | field($model, 'end_execute') ?>
49 |
50 |
51 | 'btn btn-primary']) ?>
52 | 'btn btn-default']) ?>
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/models/QueueManager.php:
--------------------------------------------------------------------------------
1 | Yii::t('queuemanager', 'Status Waiting'),
42 | self::STATUS_RESERVED => Yii::t('queuemanager', 'Status Reserved'),
43 | self::STATUS_DONE => Yii::t('queuemanager', 'Status Done'),
44 | self::STATUS_ERROR => Yii::t('queuemanager', 'Status Error'),
45 | ];
46 |
47 | return $status ? ArrayHelper::getValue($statuses, $status) : $statuses;
48 | }
49 |
50 | public function behaviors()
51 | {
52 | return ArrayHelper::merge(parent::behaviors(), [
53 | 'timestamp' => \yii\behaviors\TimestampBehavior::class,
54 | ]);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/messages/ru/queuemanager.php:
--------------------------------------------------------------------------------
1 | 'Отчет',
21 | 'Statistics' => 'Статистика',
22 | 'Enter date' => 'Укажите дату',
23 | 'Are you sure to repeat this item?' => '',
24 | 'Are you sure you want to delete this item?' => '',
25 | 'Class' => '',
26 | 'Create' => '',
27 | 'Create {modelClass}' => '',
28 | 'Created At' => '',
29 | 'Data' => '',
30 | 'Delay' => '',
31 | 'Delete' => '',
32 | 'End Execute' => '',
33 | 'ID' => '',
34 | 'Name' => '',
35 | 'Priority' => '',
36 | 'Properties' => '',
37 | 'Queue Managers' => '',
38 | 'Repeat' => '',
39 | 'Reset' => '',
40 | 'Result' => '',
41 | 'Result ID' => '',
42 | 'Search' => '',
43 | 'Sender' => '',
44 | 'Start Execute' => '',
45 | 'Status' => '',
46 | 'Status Done' => '',
47 | 'Status Error' => '',
48 | 'Status Reserved' => '',
49 | 'Status Waiting' => '',
50 | 'Time Execute' => '',
51 | 'Ttr' => '',
52 | 'Update' => '',
53 | 'Update {modelClass}: ' => '',
54 | 'Updated At' => '',
55 | ];
56 |
--------------------------------------------------------------------------------
/views/default/_form.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Yii2 Queue Manager
2 | ==================
3 |
4 | [](https://packagist.org/packages/ignatenkovnikita/yii2-queuemanager) [](https://packagist.org/packages/ignatenkovnikita/yii2-queuemanager) [](https://packagist.org/packages/ignatenkovnikita/yii2-queuemanager) [](https://packagist.org/packages/ignatenkovnikita/yii2-queuemanager)
5 |
6 |
7 | Yii2 Queue Manager
8 |
9 | 
10 |
11 |
12 | Installation
13 | ------------
14 |
15 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
16 |
17 | Either run
18 |
19 | ```
20 | php composer.phar require --prefer-dist ignatenkovnikita/yii2-queuemanager "*"
21 | ```
22 |
23 | or add
24 |
25 | ```
26 | "ignatenkovnikita/yii2-queuemanager": "*"
27 | ```
28 |
29 | to the require section of your `composer.json` file.
30 |
31 |
32 | Usage
33 | -----
34 | Apply migrations
35 |
36 | ```bash
37 | ./console/yii migrate --migrationPath=vendor/ignatenkovnikita/yii2-queuemanager/migrations/
38 |
39 | ```
40 |
41 | Once the extension is installed, simply use it in your code by :
42 |
43 | ```php
44 | 'modules' => [
45 | 'queuemanager' => [
46 | 'class' => \ignatenkovnikita\queuemanager\QueueManager::class
47 | ]
48 | ],
49 | 'components' => [
50 | 'queue' => [
51 | 'class' => \yii\queue\redis\Queue::class,
52 | 'as log' => \yii\queue\LogBehavior::class,
53 | 'as quuemanager' => \ignatenkovnikita\queuemanager\behaviors\QueueManagerBehavior::class
54 | // Other driver options
55 | ],
56 | ]```
57 |
--------------------------------------------------------------------------------
/QueueManager.php:
--------------------------------------------------------------------------------
1 |
6 | * @file QueueManager.php
7 | * @author ignatenkovnikita
8 | * @date $date$
9 | */
10 |
11 | /**
12 | * Created by PhpStorm.
13 | * User: ignatenkovnikita
14 | * Web Site: http://IgnatenkovNikita.ru
15 | */
16 |
17 | namespace ignatenkovnikita\queuemanager;
18 |
19 | use Yii;
20 | use yii\base\Application;
21 | use yii\base\BootstrapInterface;
22 | use yii\base\Event;
23 | use yii\base\Module;
24 | use yii\filters\AccessControl;
25 | use yii\helpers\ArrayHelper;
26 | use yii\queue\Queue;
27 |
28 | class QueueManager extends Module implements BootstrapInterface
29 | {
30 | public $adminPermission = 'queuemanager-module';
31 |
32 | public function behaviors()
33 | {
34 | return ArrayHelper::merge(
35 | parent::behaviors(),
36 | [
37 | 'access' => [
38 | 'class' => AccessControl::className(),
39 | 'rules' => [
40 | [
41 | 'allow' => true,
42 | 'roles' => [$this->adminPermission]
43 | ]
44 | ]
45 | ]
46 | ]
47 | );
48 | }
49 |
50 | public function init()
51 | {
52 | parent::init(); // TODO: Change the autogenerated stub
53 | $this->registerTranslations();
54 | }
55 |
56 | public function registerTranslations()
57 | {
58 | Yii::$app->i18n->translations['queuemanager'] = [
59 | 'class' => 'yii\i18n\PhpMessageSource',
60 | 'sourceLanguage' => 'en-US',
61 | 'basePath' => '@vendor/ignatenkovnikita/yii2-queuemanager/messages',
62 | ];
63 |
64 | }
65 |
66 | public function bootstrap($app)
67 | {
68 | if ($app instanceof \yii\console\Application) {
69 | $app->controllerMap[$this->id] = [
70 | 'class' => 'ignatenkovnikita\queuemanager\QueueController',
71 | ];
72 |
73 |
74 | }
75 | }
76 |
77 | }
--------------------------------------------------------------------------------
/behaviors/QueueManagerBehavior.php:
--------------------------------------------------------------------------------
1 | 'afterPush',
33 | Queue::EVENT_BEFORE_EXEC => 'beforeExec',
34 | Queue::EVENT_AFTER_EXEC => 'afterExec',
35 | Queue::EVENT_AFTER_ERROR => 'afterError',
36 | ];
37 | }
38 |
39 | public function afterPush(PushEvent $event)
40 | {
41 | QueueManagerHelper::create($event);
42 | }
43 |
44 | public function beforeExec(ExecEvent $event)
45 | {
46 | QueueManagerHelper::startExec($event);
47 | }
48 |
49 | public function afterExec(ExecEvent $event)
50 | {
51 | QueueManagerHelper::afterExec($event);
52 | }
53 |
54 | public function afterError(ExecEvent $event)
55 | {
56 | QueueManagerHelper::afterError($event);
57 |
58 | Yii::endProfile($this->getEventTitle($event), Queue::class);
59 | Yii::error($this->getEventTitle($event) . ' error ' . $event->error, Queue::class);
60 | if ($this->autoFlush) {
61 | Yii::getLogger()->flush(true);
62 | }
63 | }
64 |
65 | protected function getEventTitle(JobEvent $event)
66 | {
67 | $title = strtr('[id] name', [
68 | 'id' => $event->id,
69 | 'name' => $event->job instanceof Job ? get_class($event->job) : 'mixed data',
70 | ]);
71 | if ($event instanceof ExecEvent) {
72 | $title .= " (attempt: $event->attempt)";
73 | }
74 |
75 | return $title;
76 | }
77 | }
--------------------------------------------------------------------------------
/models/generated/QueueManager.php:
--------------------------------------------------------------------------------
1 | 255],
46 | ];
47 | }
48 |
49 | /**
50 | * @inheritdoc
51 | */
52 | public function attributeLabels()
53 | {
54 | return [
55 | 'id' => Yii::t('queuemanager', 'ID'),
56 | 'name' => Yii::t('queuemanager', 'Name'),
57 | 'sender' => Yii::t('queuemanager', 'Sender'),
58 | 'ttr' => Yii::t('queuemanager', 'Ttr'),
59 | 'delay' => Yii::t('queuemanager', 'Delay'),
60 | 'priority' => Yii::t('queuemanager', 'Priority'),
61 | 'status' => Yii::t('queuemanager', 'Status'),
62 | 'class' => Yii::t('queuemanager', 'Class'),
63 | 'properties' => Yii::t('queuemanager', 'Properties'),
64 | 'data' => Yii::t('queuemanager', 'Data'),
65 | 'result_id' => Yii::t('queuemanager', 'Result ID'),
66 | 'result' => Yii::t('queuemanager', 'Result'),
67 | 'created_at' => Yii::t('queuemanager', 'Created At'),
68 | 'updated_at' => Yii::t('queuemanager', 'Updated At'),
69 | 'start_execute' => Yii::t('queuemanager', 'Start Execute'),
70 | 'end_execute' => Yii::t('queuemanager', 'End Execute'),
71 | ];
72 | }
73 |
74 | /**
75 | * @inheritdoc
76 | * @return QueueManagerQuery the active query used by this AR class.
77 | */
78 | public static function find()
79 | {
80 | return new QueueManagerQuery(get_called_class());
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/models/search/QueueManagerSearch.php:
--------------------------------------------------------------------------------
1 | orderBy('id desc');
46 |
47 | $dataProvider = new ActiveDataProvider([
48 | 'query' => $query,
49 | ]);
50 |
51 | if (!($this->load($params) && $this->validate())) {
52 | return $dataProvider;
53 | }
54 |
55 | $query->andFilterWhere([
56 | 'id' => $this->id,
57 | 'ttr' => $this->ttr,
58 | 'delay' => $this->delay,
59 | 'priority' => $this->priority,
60 | 'result_id' => $this->result_id,
61 | // 'created_at' => $this->created_at,
62 | // 'updated_at' => $this->updated_at,
63 | 'start_execute' => $this->start_execute,
64 | 'end_execute' => $this->end_execute,
65 | ]);
66 |
67 | $this->dayCondition($query, 'created_at');
68 | $this->dayCondition($query, 'updated_at');
69 |
70 | $query->andFilterWhere(['like', 'name', $this->name])
71 | ->andFilterWhere(['like', 'sender', $this->sender])
72 | ->andFilterWhere(['like', 'status', $this->status])
73 | ->andFilterWhere(['like', 'class', $this->class])
74 | ->andFilterWhere(['like', 'properties', $this->properties])
75 | ->andFilterWhere(['like', 'data', $this->data])
76 | ->andFilterWhere(['like', 'result', $this->result]);
77 |
78 |
79 | return $dataProvider;
80 | }
81 |
82 |
83 | /**
84 | * @param ActiveQuery $query
85 | * @param $attribute
86 | * @return bool
87 | */
88 | protected function dayCondition(ActiveQuery &$query, $attribute)
89 | {
90 | if(empty($this->{$attribute})) {
91 | return false;
92 | }
93 | $start = strtotime('midnight', strtotime($this->{$attribute}));
94 | $query->andFilterWhere( ['BETWEEN', $attribute, $start, strtotime('+1day - 1sec', $start)]);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/helpers/QueueManagerHelper.php:
--------------------------------------------------------------------------------
1 | getComponents(false) as $id => $component) {
26 | if ($component === $event->sender) {
27 | $data['sender'] = $id;
28 | break;
29 | }
30 | }
31 | $data['id'] = $event->id;
32 | $data['ttr'] = isset($event->ttr) ? $event->ttr : null;
33 | $data['delay'] = isset($event->delay) ? $event->delay : null;
34 | $data['priority'] = isset($event->priority) ? $event->priority : null;
35 | // $data['status'] = self::getStatus($data);
36 | if ($event->job instanceof Job) {
37 | $data['class'] = get_class($event->job);
38 | $data['name'] = $event->job->name;
39 | $data['properties'] = [];
40 | foreach (get_object_vars($event->job) as $property => $value) {
41 | $data['properties'][$property] = VarDumper::dumpAsString($value);
42 | }
43 | } else {
44 | $data['data'] = VarDumper::dumpAsString($event->job);
45 | }
46 |
47 | return $data;
48 | }
49 |
50 | public static function create($event)
51 | {
52 | $data = self::parseDate($event);
53 | $model = QueueManager::findOne($data['id']);
54 | if (!$model) {
55 | $model = new QueueManager();
56 | $model->load($data, '');
57 | $model->id = $data['id'];
58 | $model->status = self::getStatus($model);
59 | $model->properties = json_encode($model->properties);
60 | $model->data = json_encode($model->data);
61 | $model->save();
62 | }
63 |
64 | return $model;
65 | }
66 |
67 | public static function startExec(ExecEvent $event)
68 | {
69 | $model = self::create($event);
70 | $model->start_execute = time();
71 | $model->status = self::getStatus($model);
72 | $r = $model->updateAttributes(['start_execute', 'status']);
73 | return $r;
74 | }
75 |
76 | public static function afterExec(ExecEvent $event)
77 | {
78 | $model = self::create($event);
79 | $model->end_execute = time();
80 | $model->status = QueueManager::STATUS_DONE;
81 | $r = $model->updateAttributes(['end_execute', 'status']);
82 | return $r;
83 | }
84 |
85 | public static function afterError(ExecEvent $event)
86 | {
87 | $model = self::create($event);
88 | $model->end_execute = time();
89 | $model->status = QueueManager::STATUS_ERROR;
90 | $model->result = $event->error;
91 | $r = $model->updateAttributes(['end_execute', 'status', 'result']);
92 | return $r;
93 | }
94 |
95 | private static function getStatus($model)
96 | {
97 | $status = null;
98 | if ($queue = Yii::$app->get($model->sender, false)) {
99 | try {
100 | if ($queue->isWaiting($model->id)) {
101 | $status = QueueManager::STATUS_WAITING;
102 | } elseif ($queue->isReserved($model->id)) {
103 | $status = QueueManager::STATUS_RESERVED;
104 | } elseif ($queue->isDone($model->id)) {
105 | $status = QueueManager::STATUS_DONE;
106 | }
107 | } catch (NotSupportedException $e) {
108 | } catch (\Exception $e) {
109 | $status = $e->getMessage();
110 | }
111 | }
112 | return $status;
113 | }
114 | }
--------------------------------------------------------------------------------
/js/queuemanager.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) $user$, Inc - All Rights Reserved
3 | *
4 | *
5 | * @file queuemanager.js
6 | * @author ignatenkovnikita
7 | * @date $date$
8 | */
9 |
10 |
11 | Highcharts.setOptions({
12 | global: {
13 | useUTC: false
14 | }
15 | });
16 |
17 | // Create the chart
18 | Highcharts.stockChart('container', {
19 | chart: {
20 | events: {
21 | load: function () {
22 |
23 | // set up the updating of the chart each second
24 | var series_1 = this.series[0];
25 | var series_2 = this.series[1];
26 | var series_3 = this.series[2];
27 | setInterval(function () {
28 | $.ajax({
29 | url: "ajax",
30 | method: "GET",
31 | // data: {"id": id},
32 | dataType: "json",
33 |
34 | success: function (data) {
35 | console.log(data.time);
36 | console.log(data.series_1);
37 | series_1.addPoint([(new Date()).getTime(), data.series_1], true, true);
38 | series_2.addPoint([(new Date()).getTime(), data.series_2], true, true);
39 | series_3.addPoint([(new Date()).getTime(), data.series_3], true, true);
40 |
41 | $('#workers').html(data.workers.join("
"));
42 | }
43 |
44 | });
45 |
46 | var x = (new Date()).getTime(), // current time
47 | y = Math.round(Math.random() * 100);
48 | console.log(x);
49 | // series.addPoint([x, y], true, true);
50 | }, 1000);
51 | }
52 | }
53 | },
54 |
55 | rangeSelector: {
56 | buttons: [{
57 | count: 1,
58 | type: 'minute',
59 | text: '1M'
60 | }, {
61 | count: 5,
62 | type: 'minute',
63 | text: '5M'
64 | }, {
65 | type: 'all',
66 | text: 'All'
67 | }],
68 | inputEnabled:
69 | false,
70 | selected:
71 | 0
72 | },
73 |
74 | title: {
75 | text: 'Queue Stat'
76 | }
77 | ,
78 |
79 | exporting: {
80 | enabled: false
81 | }
82 | ,
83 |
84 | series: [{
85 | name: 'Waiting',
86 | data: (function () {
87 | // generate an array of random data
88 | var data = [],
89 | time = (new Date()).getTime(),
90 | i;
91 |
92 | for (i = -5; i <= 0; i += 1) {
93 | data.push([
94 | time + i * 1000,
95 | Math.round(0)
96 | ]);
97 | }
98 | return data;
99 | }())
100 | },
101 | {
102 | name: 'Delayed',
103 | data: (function () {
104 | // generate an array of random data
105 | var data = [],
106 | time = (new Date()).getTime(),
107 | i;
108 |
109 | for (i = -5; i <= 0; i += 1) {
110 | data.push([
111 | time + i * 1000,
112 | Math.round(0)
113 | ]);
114 | }
115 | return data;
116 | }())
117 | },
118 | {
119 | name: 'Reserved',
120 | data: (function () {
121 | // generate an array of random data
122 | var data = [],
123 | time = (new Date()).getTime(),
124 | i;
125 |
126 | for (i = -5; i <= 0; i += 1) {
127 | data.push([
128 | time + i * 1000,
129 | Math.round(0)
130 | ]);
131 | }
132 | return data;
133 | }())
134 | }
135 | ]
136 | })
137 | ;
138 |
139 |
--------------------------------------------------------------------------------
/views/default/report.php:
--------------------------------------------------------------------------------
1 |
6 | * @file report.php
7 | * @author ignatenkovnikita
8 | * @date $date$
9 | */
10 |
11 | use dosamigos\chartjs\ChartJs;
12 | use ignatenkovnikita\queuemanager\models\QueueManager;
13 |
14 | /**
15 | * Created by PhpStorm.
16 | * User: ignatenkovnikita
17 | * Web Site: http://IgnatenkovNikita.ru
18 | */
19 |
20 | $this->title = 'Report status job';
21 | $this->params['breadcrumbs'][] = ['label' => Yii::t('queuemanager', 'Queue Managers'), 'url' => ['index']];
22 | $this->params['breadcrumbs'][] = $this->title;
23 |
24 |
25 | // status
26 | $db = Yii::$app->db;
27 | switch ($db->driverName) {
28 | case 'pgsql':
29 | $selectExpression = "to_char(to_timestamp(created_at), 'YYYY-MM-DD')";
30 | break;
31 | default:
32 | case 'mysql':
33 | $selectExpression = "DATE_FORMAT(FROM_UNIXTIME(created_at), '%Y-%m-%d')";
34 | break;
35 | }
36 | $subQuery = (new \yii\db\Query())
37 | ->select([
38 | 'dd' => new \yii\db\Expression($selectExpression),
39 | 'status',
40 | ])->from('queue_manager');
41 | $data = (new \yii\db\Query())
42 | ->select([
43 | 'dd',
44 | 'status',
45 | 'cnt' => 'COUNT(*)',
46 | ])
47 | ->from(['q' => $subQuery])
48 | ->groupBy(['status', 'dd'])
49 | ->orderBy('dd')
50 | ->all();
51 |
52 | $labels = [];
53 | foreach ($data as $item) {
54 | $dd = Yii::$app->formatter->asDate($item['dd']);
55 | if (!in_array($dd, $labels)) {
56 | $labels[] = $dd;
57 | }
58 | }
59 | $status1 = array_fill_keys($labels, '0');
60 | $status2 = array_fill_keys($labels, '0');
61 | $status3 = array_fill_keys($labels, '0');
62 | $status4 = array_fill_keys($labels, '0');
63 | foreach ($data as $item) {
64 | $dd = Yii::$app->formatter->asDate($item['dd']);
65 | if ($item['status'] == QueueManager::STATUS_WAITING) {
66 | $status1[$dd] = $item['cnt'];
67 | }
68 | if ($item['status'] == QueueManager::STATUS_RESERVED) {
69 | $status2[$dd] = $item['cnt'];
70 | }
71 | if ($item['status'] == QueueManager::STATUS_DONE) {
72 | $status3[$dd] = $item['cnt'];
73 | }
74 | if ($item['status'] == QueueManager::STATUS_ERROR) {
75 | $status4[$dd] = $item['cnt'];
76 | }
77 | }
78 | $status1 = array_values($status1);
79 | $status2 = array_values($status2);
80 | $status3 = array_values($status3);
81 | $status4 = array_values($status4);
82 |
83 |
84 | echo ChartJs::widget([
85 | 'type' => 'line',
86 | 'options' => [
87 | // 'height' => 400,
88 | // 'width' => 400
89 | ],
90 | 'data' => [
91 | 'labels' => $labels,
92 | 'datasets' => [
93 | [
94 | 'label' => "Status Waiting",
95 | // 'backgroundColor' => "rgba(179,181,198,0.2)",
96 | 'borderColor' => "blue",
97 | // 'pointBackgroundColor' => "rgba(179,181,198,1)",
98 | // 'pointBorderColor' => "#fff",
99 | // 'pointHoverBackgroundColor' => "#fff",
100 | // 'pointHoverBorderColor' => "rgba(179,181,198,1)",
101 | 'data' => $status1
102 | ],
103 | [
104 | 'label' => "Status Reserved",
105 | // 'backgroundColor' => "rgba(255,99,132,0.2)",
106 | 'borderColor' => "green",
107 | // 'pointBackgroundColor' => "rgba(255,99,132,1)",
108 | // 'pointBorderColor' => "#fff",
109 | // 'pointHoverBackgroundColor' => "#fff",
110 | // 'pointHoverBorderColor' => "rgba(255,99,132,1)",
111 | 'data' => $status2
112 | ],
113 | [
114 | 'label' => "Status Done",
115 | // 'backgroundColor' => "rgba(255,99,132,0.2)",
116 | 'borderColor' => "green",
117 | // 'pointBackgroundColor' => "rgba(255,99,132,1)",
118 | // 'pointBorderColor' => "#fff",
119 | // 'pointHoverBackgroundColor' => "#fff",
120 | // 'pointHoverBorderColor' => "rgba(255,99,132,1)",
121 | 'data' => $status3
122 | ],
123 | [
124 | 'label' => "Status Error",
125 | // 'backgroundColor' => "rgba(255,99,132,0.2)",
126 | 'borderColor' => "red",
127 | // 'pointBackgroundColor' => "rgba(255,99,132,1)",
128 | // 'pointBorderColor' => "#fff",
129 | // 'pointHoverBackgroundColor' => "#fff",
130 | // 'pointHoverBorderColor' => "rgba(255,99,132,1)",
131 | 'data' => $status4
132 | ]
133 | ]
134 | ]
135 | ]);
--------------------------------------------------------------------------------
/views/default/index.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('queuemanager', 'Queue Managers');
13 | $this->params['breadcrumbs'][] = $this->title;
14 | ?>
15 |
16 |
17 | render('_search', ['model' => $searchModel]); ?>
18 |
19 | = Html::a(Yii::t('queuemanager', 'Report'), ['report']) ?>
20 | = Html::a(Yii::t('queuemanager', 'Statistics'), ['stat']) ?>
21 |
22 | $dataProvider,
27 | 'filterModel' => $searchModel,
28 | 'rowOptions' => function ($model) {
29 | if ($model->status == QueueManager::STATUS_DONE) {
30 | return ['class' => 'success'];
31 | }
32 | if ($model->status == QueueManager::STATUS_RESERVED) {
33 | return ['class' => 'warning'];
34 | }
35 | if ($model->status == QueueManager::STATUS_WAITING) {
36 | return ['class' => 'info'];
37 | }
38 | if ($model->status == QueueManager::STATUS_ERROR) {
39 | return ['class' => 'danger'];
40 | }
41 | },
42 | 'columns' => [
43 | // ['class' => 'yii\grid\SerialColumn'],
44 |
45 | 'id',
46 | [
47 | 'attribute' => 'status',
48 | 'value' => function ($data) {
49 | return QueueManager::getStatuses($data->status);
50 | },
51 | 'filter' => QueueManager::getStatuses()
52 | ],
53 | 'name',
54 | 'sender',
55 | // 'ttr',
56 | // 'delay',
57 | // 'priority',
58 | // 'status',
59 | // 'class',
60 | // 'properties:ntext',
61 | // 'data:ntext',
62 | // 'result_id',
63 | // 'result:ntext',
64 | [
65 | 'headerOptions' => ['width' => '140'],
66 | 'attribute' => 'created_at',
67 | 'value' => function ($model) {
68 |
69 | return empty($model->created_at) ? null : date('d.m.Y H:i:s', $model->created_at);
70 | },
71 | 'filter' => DatePicker::widget([
72 | 'model' => $searchModel,
73 | 'attribute' => 'created_at',
74 | 'dateFormat' => 'php:d.m.Y',
75 | 'options' => ['class' => 'form-control', 'placeholder' => Yii::t('queuemanager', 'Enter date')],
76 | ]),
77 | 'format' => 'html',
78 | ],
79 | [
80 | 'headerOptions' => ['width' => '140'],
81 | 'attribute' => 'updated_at',
82 | 'value' => function ($model) {
83 |
84 | return empty($model->created_at) ? null : date('d.m.Y H:i:s', $model->created_at);
85 | },
86 | 'filter' => DatePicker::widget([
87 | 'model' => $searchModel,
88 | 'attribute' => 'updated_at',
89 | 'dateFormat' => 'php:d.m.Y',
90 | 'options' => ['class' => 'form-control', 'placeholder' => Yii::t('queuemanager', 'Enter date')],
91 | ]),
92 | 'format' => 'html',
93 | ],
94 | // 'updated_at',
95 | 'start_execute:datetime',
96 | 'end_execute:datetime',
97 | [
98 | 'label' => Yii::t('queuemanager', 'Time Execute'),
99 | 'value' => function (\ignatenkovnikita\queuemanager\models\QueueManager $data) {
100 | return Yii::$app->formatter->asTimestamp($data->end_execute - $data->start_execute);
101 | }
102 | ],
103 |
104 | [
105 | 'class' => 'yii\grid\ActionColumn',
106 | 'template' => '{view} {repeat} {delete}',
107 | 'buttons' => [
108 | 'repeat' => function ($url, $model) {
109 | $customurl = Yii::$app->getUrlManager()->createUrl(['default/repeat', 'id' => $model['id']]); //$model->id для AR
110 | // return \yii\helpers\Html::a('', $customurl,
111 | // ['title' => Yii::t('queuemanager', 'Repeat'), 'data-pjax' => '0']);
112 | return Html::a('', $url, [
113 | 'title' => Yii::t('queuemanager', 'Repeat'),
114 | 'data-confirm' => Yii::t('queuemanager', 'Are you sure to repeat this item?'),
115 | 'data-method' => 'post',
116 | ]);
117 | }
118 |
119 |
120 | ]
121 | ],
122 | ],
123 | ]);
124 | \yii\widgets\Pjax::end();
125 | ?>
126 |
127 |
128 |
129 | registerJs('
132 | setInterval(function(){
133 | $.pjax.reload({container:"#p0"});
134 | }, 3000);', \yii\web\VIEW::POS_HEAD);
135 | ?>
136 |
--------------------------------------------------------------------------------
/controllers/DefaultController.php:
--------------------------------------------------------------------------------
1 | [
26 | 'class' => VerbFilter::className(),
27 | 'actions' => [
28 | 'delete' => ['post'],
29 | 'repeat' => ['post'],
30 | ],
31 | ],
32 | ];
33 | }
34 |
35 | /**
36 | * Lists all QueueManager models.
37 | * @return mixed
38 | */
39 | public function actionIndex()
40 | {
41 | $searchModel = new QueueManagerSearch();
42 | $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
43 |
44 | return $this->render('index', [
45 | 'searchModel' => $searchModel,
46 | 'dataProvider' => $dataProvider,
47 | ]);
48 | }
49 |
50 | /**
51 | * @return array
52 | */
53 | protected function getWorkersInfo()
54 | {
55 | $queue = Yii::$app->queue;
56 |
57 | $workers = [];
58 | $data = $queue->redis->clientList();
59 | foreach (explode("\n", trim($data)) as $line) {
60 | $client = [];
61 | foreach (explode(' ', trim($line)) as $pair) {
62 | list($key, $value) = explode('=', $pair, 2);
63 | $client[$key] = $value;
64 | }
65 | if (isset($client['name']) && strpos($client['name'], $queue->channel . '.worker') === 0) {
66 | $workers[$client['name']] = $client;
67 | }
68 | }
69 |
70 | return $workers;
71 | }
72 |
73 |
74 | /**
75 | * @return array
76 | */
77 | public function actionAjax()
78 | {
79 | $workers = [];
80 | if ($workersInfo = $this->getWorkersInfo()) {
81 | foreach ($workersInfo as $name => $info) {
82 | $workers[] = $name . ' ' . $info['addr'];
83 | // Console::stdout($this->format("- $name: ", Console::FG_YELLOW));
84 | // Console::output($info['addr']);
85 | }
86 | }
87 |
88 | $queue = Yii::$app->queue;
89 | $prefix = $queue->channel;
90 | $waiting = $queue->redis->llen("$prefix.waiting");
91 | $delayed = $queue->redis->zcount("$prefix.delayed", '-inf', '+inf');
92 | $reserved = $queue->redis->zcount("$prefix.reserved", '-inf', '+inf');
93 | $total = $queue->redis->get("$prefix.message_id");
94 | $done = $total - $waiting - $delayed - $reserved;
95 |
96 | Yii::$app->response->format = Response::FORMAT_JSON;
97 |
98 | return [
99 | 'time' => time(),
100 | 'series_1' => (int)$waiting,
101 | 'series_2' => (int)$delayed,
102 | 'series_3' => (int)$reserved,
103 | 'workers' => $workers
104 | ];
105 | }
106 |
107 |
108 | public function actionStat()
109 | {
110 | return $this->render('stat');
111 | }
112 |
113 | public function actionReport()
114 | {
115 | return $this->render('report');
116 | }
117 |
118 | /**
119 | * Displays a single QueueManager model.
120 | * @param integer $id
121 | * @return mixed
122 | */
123 | public function actionView($id)
124 | {
125 | return $this->render('view', [
126 | 'model' => $this->findModel($id),
127 | ]);
128 | }
129 |
130 | /**
131 | * Creates a new QueueManager model.
132 | * If creation is successful, the browser will be redirected to the 'view' page.
133 | * @return mixed
134 | */
135 | public function actionCreate()
136 | {
137 | $model = new QueueManager();
138 |
139 | if ($model->load(Yii::$app->request->post()) && $model->save()) {
140 | return $this->redirect(['view', 'id' => $model->id]);
141 | } else {
142 | return $this->render('create', [
143 | 'model' => $model,
144 | ]);
145 | }
146 | }
147 |
148 | /**
149 | * Updates an existing QueueManager model.
150 | * If update is successful, the browser will be redirected to the 'view' page.
151 | * @param integer $id
152 | * @return mixed
153 | */
154 | public function actionUpdate($id)
155 | {
156 | $model = $this->findModel($id);
157 |
158 | if ($model->load(Yii::$app->request->post()) && $model->save()) {
159 | return $this->redirect(['view', 'id' => $model->id]);
160 | } else {
161 | return $this->render('update', [
162 | 'model' => $model,
163 | ]);
164 | }
165 | }
166 |
167 | /**
168 | * Deletes an existing QueueManager model.
169 | * If deletion is successful, the browser will be redirected to the 'index' page.
170 | * @param integer $id
171 | * @return mixed
172 | */
173 | public function actionDelete($id)
174 | {
175 | $this->findModel($id)->delete();
176 |
177 | return $this->redirect(['index']);
178 | }
179 |
180 | public function actionRepeat($id)
181 | {
182 | $model = $this->findModel($id);
183 |
184 |
185 | Yii::$app->{$model->sender}->push(new $model->class(json_decode($model->properties)));
186 | return $this->redirect(Yii::$app->request->referrer);
187 | // Yii::$app->components->->push()
188 | // print_r($model);
189 | }
190 |
191 | /**
192 | * Finds the QueueManager model based on its primary key value.
193 | * If the model is not found, a 404 HTTP exception will be thrown.
194 | * @param integer $id
195 | * @return QueueManager the loaded model
196 | * @throws NotFoundHttpException if the model cannot be found
197 | */
198 | protected function findModel($id)
199 | {
200 | if (($model = QueueManager::findOne($id)) !== null) {
201 | return $model;
202 | } else {
203 | throw new NotFoundHttpException('The requested page does not exist.');
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------