Skip to content

Commit 729718a

Browse files
authored
Merge pull request #127 from Ethan3600/1.x-develop
Release 1.9.0
2 parents d2b3792 + aa22421 commit 729718a

25 files changed

+1163
-28
lines changed

.travis.yml

+20
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,42 @@ matrix:
1717
env:
1818
- MAGENTO_VERSION=2.3
1919
- TEST_SUITE=integration
20+
- php: 7.2
21+
env:
22+
- MAGENTO_VERSION=2.3
23+
- TEST_SUITE=unit
2024
- php: 7.2
2125
env:
2226
- MAGENTO_VERSION=2.3-develop
2327
- TEST_SUITE=integration
28+
- php: 7.2
29+
env:
30+
- MAGENTO_VERSION=2.3-develop
31+
- TEST_SUITE=unit
2432
- php: 7.1
2533
env:
2634
- MAGENTO_VERSION=2.3-develop
2735
- TEST_SUITE=integration
36+
- php: 7.1
37+
env:
38+
- MAGENTO_VERSION=2.3-develop
39+
- TEST_SUITE=unit
2840
- php: 7.1
2941
env:
3042
- MAGENTO_VERSION=2.2-develop
3143
- TEST_SUITE=integration
44+
- php: 7.1
45+
env:
46+
- MAGENTO_VERSION=2.2-develop
47+
- TEST_SUITE=unit
3248
- php: 7.1
3349
env:
3450
- MAGENTO_VERSION=2.2
3551
- TEST_SUITE=integration
52+
- php: 7.1
53+
env:
54+
- MAGENTO_VERSION=2.2
55+
- TEST_SUITE=unit
3656
env:
3757
global:
3858
- COMPOSER_BIN_DIR=~/bin

.travis/before_script.sh

+3-13
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,12 @@ cd magento2
2424

2525
# add composer package under test, composer require will trigger update/install
2626
case $TRAVIS_BRANCH in
27-
1.x)
27+
"1.x" | "0.x")
2828
composer config minimum-stability dev
2929
composer config repositories.travis_to_test git https://github.com/$TRAVIS_REPO_SLUG.git
3030
composer require ${COMPOSER_PACKAGE_NAME}:${TRAVIS_BRANCH}-dev\#{$TRAVIS_COMMIT}
3131
;;
32-
1.x-develop)
33-
composer config minimum-stability dev
34-
composer config repositories.travis_to_test git https://github.com/$TRAVIS_REPO_SLUG.git
35-
composer require ${COMPOSER_PACKAGE_NAME}:dev-${TRAVIS_BRANCH}\#{$TRAVIS_COMMIT}
36-
;;
37-
0.x)
38-
composer config minimum-stability dev
39-
composer config repositories.travis_to_test git https://github.com/$TRAVIS_REPO_SLUG.git
40-
composer require ${COMPOSER_PACKAGE_NAME}:${TRAVIS_BRANCH}-dev\#{$TRAVIS_COMMIT}
41-
;;
42-
0.x-develop)
32+
*)
4333
composer config minimum-stability dev
4434
composer config repositories.travis_to_test git https://github.com/$TRAVIS_REPO_SLUG.git
4535
composer require ${COMPOSER_PACKAGE_NAME}:dev-${TRAVIS_BRANCH}\#{$TRAVIS_COMMIT}
@@ -65,5 +55,5 @@ case $TEST_SUITE in
6555
;;
6656
unit)
6757
cp vendor/$COMPOSER_PACKAGE_NAME/Test/Unit/phpunit.xml.dist dev/tests/unit/phpunit.xml
68-
;;
58+
;;
6959
esac

Console/Command/KillJob.php

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace EthanYehuda\CronjobManager\Console\Command;
5+
6+
use Magento\Framework\App\State;
7+
use Magento\Framework\App\Area;
8+
use Magento\Framework\Console\Cli;
9+
use Magento\Framework\Exception\LocalizedException;
10+
use Magento\Framework\Api\Search\FilterGroupBuilder;
11+
use Magento\Framework\Api\FilterBuilder;
12+
use Magento\Framework\Api\SearchCriteriaBuilder;
13+
use Magento\Framework\Api\SearchCriteria;
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputArgument;
16+
use Symfony\Component\Console\Input\InputOption;
17+
use Symfony\Component\Console\Input\InputInterface;
18+
use Symfony\Component\Console\Output\OutputInterface;
19+
use EthanYehuda\CronjobManager\Api\ScheduleRepositoryInterface;
20+
use EthanYehuda\CronjobManager\Api\ScheduleManagementInterface\Proxy as ScheduleManagementInterface;
21+
use EthanYehuda\CronjobManager\Model\ProcessManagement;
22+
use EthanYehuda\CronjobManager\Model\Data\Schedule;
23+
24+
class KillJob extends Command
25+
{
26+
const INPUT_KEY_JOB_CODE = 'job_code';
27+
28+
const OPTION_KEY_PROC_KILL = 'process-kill';
29+
30+
/**
31+
* @var State
32+
*/
33+
private $state;
34+
35+
/**
36+
* @var ScheduleRepositoryInterface
37+
*/
38+
private $scheduleRepository;
39+
40+
/**
41+
* @var ScheduleManagementInterface
42+
*/
43+
private $scheduleManagement;
44+
45+
/**
46+
* @var SearchCriteriaBuilder
47+
*/
48+
private $searchCriteriaBuilder;
49+
50+
/**
51+
* @var FilterBuilder
52+
*/
53+
private $filterBuilder;
54+
55+
/**
56+
* @var FilterGroupBuilder
57+
*/
58+
private $filterGroupBuilder;
59+
60+
/**
61+
* @var ProcessManagement
62+
*/
63+
private $processManagement;
64+
65+
/**
66+
* @var string[]
67+
*/
68+
private $errors = [];
69+
70+
public function __construct(
71+
State $state,
72+
ScheduleRepositoryInterface $scheduleRepository,
73+
ScheduleManagementInterface $scheduleManagement,
74+
SearchCriteriaBuilder $searchCriteriaBuilder,
75+
FilterBuilder $filterBuilder,
76+
FilterGroupBuilder $filterGroupBuilder,
77+
ProcessManagement $processManagement
78+
) {
79+
$this->state = $state;
80+
$this->scheduleRepository = $scheduleRepository;
81+
$this->scheduleManagement = $scheduleManagement;
82+
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
83+
$this->filterBuilder = $filterBuilder;
84+
$this->filterGroupBuilder = $filterGroupBuilder;
85+
$this->processManagement = $processManagement;
86+
parent::__construct();
87+
}
88+
89+
protected function configure()
90+
{
91+
$arguments = [
92+
new InputArgument(
93+
self::INPUT_KEY_JOB_CODE,
94+
InputArgument::REQUIRED,
95+
"Job code input (ex. 'sitemap_generate')
96+
\nSends \"kill request\" to all the cron jobs given a specified job_code.
97+
\nKill requests will not kill jobs immediately; instead it will be scheduled to be killed and handled by Magento's cron scheduler"
98+
),
99+
new InputOption(
100+
self::OPTION_KEY_PROC_KILL,
101+
"p",
102+
InputOption::VALUE_NONE,
103+
"Sends a kill request immediately to the job processes that are running the given job_code"
104+
)
105+
];
106+
107+
$this->setName("cronmanager:killjob");
108+
$this->setDescription("Kill cron jobs by code");
109+
$this->setDefinition($arguments);
110+
parent::configure();
111+
}
112+
113+
protected function execute(InputInterface $input, OutputInterface $output)
114+
{
115+
try {
116+
$this->state->setAreaCode(Area::AREA_ADMINHTML);
117+
} catch (LocalizedException $exception) {
118+
// Area code is already set
119+
}
120+
121+
/** @var string $jobCode */
122+
$jobCode = $input->getArgument(self::INPUT_KEY_JOB_CODE);
123+
124+
/** @var bool $optionProcKill */
125+
$optionProcKill = $input->getOption(self::OPTION_KEY_PROC_KILL);
126+
127+
/** @var Schedule[] $runningJobs */
128+
$runningJobs = $this->loadRunningJobsByCode($jobCode);
129+
130+
/** @var Schedule $job */
131+
foreach ($runningJobs as $job) {
132+
/** @var int $id */
133+
$id = (int)$job->getScheduleId();
134+
/** @var int $pid */
135+
$pid = (int)$job->getPid();
136+
if ($id !== null && $pid !== null) {
137+
/** @var bool $killed */
138+
$killed = false;
139+
if ($optionProcKill) {
140+
$killed = $this->processManagement->killPid($pid);
141+
} else {
142+
$killed = $this->scheduleManagement->kill($id, \time());
143+
}
144+
145+
if (!$killed) {
146+
$this->errors[] = "Unable to kill {$job->getJobCode()} with PID: $pid";
147+
}
148+
}
149+
}
150+
151+
if (\count($this->errors) > 0) {
152+
foreach ($this->errors as $error) {
153+
/** @var string $error */
154+
$output->writeln($error);
155+
}
156+
return Cli::RETURN_FAILURE;
157+
}
158+
$output->writeln("$jobCode successfully killed");
159+
return Cli::RETURN_SUCCESS;
160+
}
161+
162+
/**
163+
* @return Schedule[]
164+
*/
165+
private function loadRunningJobsByCode(string $jobCode): array
166+
{
167+
/** @var AbstractSimpleObject $jobCode */
168+
$jobCodeFilter = $this->filterBuilder
169+
->setField(Schedule::KEY_JOB_CODE)
170+
->setConditionType('eq')
171+
->setValue($jobCode)
172+
->create();
173+
/** @var AbstractSimpleObject $jobCodeFilterGroup */
174+
$jobCodeFilterGroup = $this->filterGroupBuilder
175+
->addFilter($jobCodeFilter)
176+
->create();
177+
178+
/** @var AbstractSimpleObject $jobCode */
179+
$statusFilter = $this->filterBuilder
180+
->setField(Schedule::KEY_STATUS)
181+
->setConditionType('eq')
182+
->setValue(Schedule::STATUS_RUNNING)
183+
->create();
184+
/** @var AbstractSimpleObject $statusFilterGroup */
185+
$statusFilterGroup = $this->filterGroupBuilder
186+
->addFilter($statusFilter)
187+
->create();
188+
189+
/** @var SearchCriteria $searchCriteria */
190+
$searchCriteria = $this->searchCriteriaBuilder->setFilterGroups(
191+
[$jobCodeFilterGroup, $statusFilterGroup]
192+
)->create();
193+
194+
/** @var \Magento\Framework\Api\SearchResultsInterface $result */
195+
$result = $this->scheduleRepository->getList($searchCriteria);
196+
return $result->getItems();
197+
}
198+
}

Model/ErrorNotification.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace EthanYehuda\CronjobManager\Model;
5+
6+
use Magento\Cron\Model\Schedule;
7+
8+
interface ErrorNotification
9+
{
10+
public function sendFor(Schedule $schedule): void;
11+
}

Model/ErrorNotificationEmail.php

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace EthanYehuda\CronjobManager\Model;
5+
6+
use Magento\Cron\Model\Schedule;
7+
use Magento\Framework\App\Area;
8+
use Magento\Framework\App\Config\ScopeConfigInterface;
9+
use Magento\Framework\Mail\Template\SenderResolverInterface;
10+
use Magento\Framework\Mail\Template\TransportBuilder;
11+
use Magento\Store\Model\StoreManagerInterface;
12+
use Psr\Log\LoggerInterface;
13+
14+
class ErrorNotificationEmail implements ErrorNotification
15+
{
16+
private const XML_PATH_EMAIL_ENABLED = 'system/cron_job_manager/email_notification';
17+
private const XML_PATH_EMAIL_TEMPLATE = 'system/cron_job_manager/email_template';
18+
private const XML_PATH_EMAIL_IDENTITY = 'system/cron_job_manager/email_identity';
19+
private const XML_PATH_EMAIL_RECIPIENTS = 'system/cron_job_manager/email_recipients';
20+
21+
/**
22+
* @var TransportBuilder
23+
*/
24+
private $mailTransportBuilder;
25+
/**
26+
* @var StoreManagerInterface
27+
*/
28+
private $storeManager;
29+
/**
30+
* @var ScopeConfigInterface
31+
*/
32+
private $scopeConfig;
33+
/**
34+
* @var SenderResolverInterface
35+
*/
36+
private $senderResolver;
37+
/**
38+
* @var LoggerInterface
39+
*/
40+
private $logger;
41+
42+
/**
43+
* ErrorNotificationEmail constructor.
44+
* @param TransportBuilder $mailTransportBuilder
45+
*/
46+
public function __construct(
47+
TransportBuilder $mailTransportBuilder,
48+
StoreManagerInterface $storeManager,
49+
ScopeConfigInterface $scopeConfig,
50+
SenderResolverInterface $senderResolver,
51+
LoggerInterface $logger
52+
) {
53+
$this->mailTransportBuilder = $mailTransportBuilder;
54+
$this->storeManager = $storeManager;
55+
$this->scopeConfig = $scopeConfig;
56+
$this->senderResolver = $senderResolver;
57+
$this->logger = $logger;
58+
}
59+
60+
public function sendFor(Schedule $schedule): void
61+
{
62+
if (!$this->scopeConfig->isSetFlag(self::XML_PATH_EMAIL_ENABLED)) {
63+
return;
64+
}
65+
try {
66+
$recipients = explode(',', (string)$this->scopeConfig->getValue(self::XML_PATH_EMAIL_RECIPIENTS));
67+
$recipients = array_map('trim', $recipients);
68+
$sender = $this->senderResolver->resolve(
69+
$this->scopeConfig->getValue(self::XML_PATH_EMAIL_IDENTITY)
70+
);
71+
72+
$this->mailTransportBuilder->setTemplateIdentifier($this->scopeConfig->getValue(self::XML_PATH_EMAIL_TEMPLATE));
73+
$this->mailTransportBuilder->setTemplateVars(['schedule' => $schedule]);
74+
$this->mailTransportBuilder->setTemplateOptions(
75+
[
76+
'area' => Area::AREA_ADMINHTML,
77+
'store' => $this->storeManager->getDefaultStoreView()->getId(),
78+
]
79+
);
80+
$this->mailTransportBuilder->setFrom($sender);
81+
$this->mailTransportBuilder->addTo($recipients);
82+
$this->mailTransportBuilder->getTransport()->sendMessage();
83+
} catch (\Exception $e) {
84+
$this->logger->error($e);
85+
}
86+
}
87+
88+
}

Model/ProcessManagement.php

-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,5 @@ public function killPid($pid): bool
2626
}
2727
}
2828
return $killed;
29-
3029
}
3130
}

Model/ScheduleManagement.php

-1
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,4 @@ public function kill(int $jobId, int $timestamp): bool
142142
$this->scheduleRepository->save($schedule);
143143
return true;
144144
}
145-
146145
}

0 commit comments

Comments
 (0)