cron data as object

This commit is contained in:
yuri
2017-12-08 14:27:12 +02:00
parent 53fb2513d4
commit 3cfae1964e
13 changed files with 149 additions and 182 deletions
+64 -70
View File
@@ -44,6 +44,10 @@ class CronManager
private $scheduledJobUtil;
private $cronJobUtil;
private $cronScheduledJobUtil;
const PENDING = 'Pending';
const RUNNING = 'Running';
@@ -64,8 +68,8 @@ class CronManager
$this->serviceFactory = $this->container->get('serviceFactory');
$this->scheduledJobUtil = $this->container->get('scheduledJob');
$this->cronJob = new \Espo\Core\Utils\Cron\Job($this->config, $this->entityManager);
$this->cronScheduledJob = new \Espo\Core\Utils\Cron\ScheduledJob($this->config, $this->entityManager);
$this->cronJobUtil = new \Espo\Core\Utils\Cron\Job($this->config, $this->entityManager);
$this->cronScheduledJobUtil = new \Espo\Core\Utils\Cron\ScheduledJob($this->config, $this->entityManager);
}
protected function getContainer()
@@ -98,14 +102,14 @@ class CronManager
return $this->scheduledJobUtil;
}
protected function getCronJob()
protected function getCronJobUtil()
{
return $this->cronJob;
return $this->cronJobUtil;
}
protected function getCronScheduledJob()
protected function getCronScheduledJobUtil()
{
return $this->cronScheduledJob;
return $this->cronScheduledJobUtil;
}
protected function getLastRunTime()
@@ -155,58 +159,44 @@ class CronManager
$this->setLastRunTime(time());
$this->getCronJob()->markFailedJobs();
$this->getCronJob()->updateFailedJobAttempts();
$this->getCronJobUtil()->markFailedJobs();
$this->getCronJobUtil()->updateFailedJobAttempts();
$this->createJobsFromScheduledJobs();
$this->getCronJob()->removePendingJobDuplicates();
$this->getCronJobUtil()->removePendingJobDuplicates();
$pendingJobList = $this->getCronJob()->getPendingJobList();
$pendingJobList = $this->getCronJobUtil()->getPendingJobList();
foreach ($pendingJobList as $job) {
$jobEntity = $this->getEntityManager()->getEntity('Job', $job['id']);
if (!isset($jobEntity)) {
$GLOBALS['log']->error('CronManager: empty Job entity ['.$job['id'].'].');
continue;
}
$jobEntity->set('status', self::RUNNING);
$this->getEntityManager()->saveEntity($jobEntity);
$job->set('status', self::RUNNING);
$this->getEntityManager()->saveEntity($job);
$isSuccess = true;
try {
if (!empty($job['scheduled_job_id'])) {
if ($job->get('scheduledJobId')) {
$this->runScheduledJob($job);
} else {
$this->runService($job);
}
} catch (\Exception $e) {
$isSuccess = false;
$GLOBALS['log']->error('CronManager: Failed job running, job ['.$job['id'].']. Error Details: '.$e->getMessage());
$GLOBALS['log']->error('CronManager: Failed job running, job ['.$job->id.']. Error Details: '.$e->getMessage());
}
$status = $isSuccess ? self::SUCCESS : self::FAILED;
$jobEntity->set('status', $status);
$this->getEntityManager()->saveEntity($jobEntity);
$job->set('status', $status);
$this->getEntityManager()->saveEntity($job);
if (!empty($job['scheduled_job_id'])) {
$this->getCronScheduledJob()->addLogRecord($job['scheduled_job_id'], $status, null, $job['target_id'], $job['target_type']);
if ($job->get('scheduledJobId')) {
$this->getCronScheduledJobUtil()->addLogRecord($job->get('scheduledJobId'), $status, null, $job->get('targetId'), $job->get('targetType'));
}
}
}
/**
* Run Scheduled Job
*
* @param array $job
*
* @return void
*/
protected function runScheduledJob(array $job)
protected function runScheduledJob($job)
{
$jobName = $job['method'];
$jobName = $job->get('scheduledJobJob');
$className = $this->getScheduledJobUtil()->get($jobName);
if ($className === false) {
@@ -220,14 +210,12 @@ class CronManager
}
$data = null;
if (!empty($job['data'])) {
$data = $job['data'];
if (Json::isJSON($data)) {
$data = Json::decode($data, true);
}
if ($job->get('data')) {
$data = $job->get('data');
}
$jobClass->$method($data, $job['target_id'], $job['target_type']);
$jobClass->$method($data, $job->get('targetId'), $job->get('targetType'));
}
/**
@@ -237,62 +225,74 @@ class CronManager
*
* @return void
*/
protected function runService(array $job)
protected function runService($job)
{
$serviceName = $job['service_name'];
$serviceName = $job->get('serviceName');
if (!$serviceName) {
throw new Error('Job with empty serviceName.');
}
if (!$this->getServiceFactory()->checkExists($serviceName)) {
throw new NotFound();
}
$service = $this->getServiceFactory()->create($serviceName);
$serviceMethod = $job['method'];
if (!method_exists($service, $serviceMethod)) {
$methodNameDeprecated = $job->get('method');
$methodName = $job->get('methodName');
$isDeprecated = false;
if (!$methodName) {
$isDeprecated = true;
$methodName = $methodNameDeprecated;
}
if (!$methodName) {
throw new Error('Job with empty methodName.');
}
if (!method_exists($service, $methodName)) {
throw new NotFound();
}
$data = $job['data'];
if (Json::isJSON($data)) {
$data = Json::decode($data, true);
$data = $job->get('data');
if ($isDeprecated) {
$data = Json::decode(Json::encode($data), true);
}
$service->$serviceMethod($data, $job['target_id'], $job['target_type']);
$service->$methodName($data, $job->get('targetId'), $job->get('targetType'));
}
/**
* Check scheduled jobs and create related jobs
*
* @return array List of created Jobs
*/
protected function createJobsFromScheduledJobs()
{
$activeScheduledJobList = $this->getCronScheduledJob()->getActiveScheduledJobList();
$activeScheduledJobList = $this->getCronScheduledJobUtil()->getActiveScheduledJobList();
$runningScheduledJobIdList = $this->getCronJob()->getRunningScheduledJobIdList();
$runningScheduledJobIdList = $this->getCronJobUtil()->getRunningScheduledJobIdList();
$createdJobIdList = array();
foreach ($activeScheduledJobList as $scheduledJob) {
$scheduling = $scheduledJob['scheduling'];
$scheduling = $scheduledJob->get('scheduling');
try {
$cronExpression = \Cron\CronExpression::factory($scheduling);
} catch (\Exception $e) {
$GLOBALS['log']->error('CronManager (ScheduledJob ['.$scheduledJob['id'].']): Scheduling string error - '. $e->getMessage() . '.');
$GLOBALS['log']->error('CronManager (ScheduledJob ['.$scheduledJob->id.']): Scheduling string error - '. $e->getMessage() . '.');
continue;
}
try {
$nextDate = $cronExpression->getNextRunDate()->format('Y-m-d H:i:s');
} catch (\Exception $e) {
$GLOBALS['log']->error('CronManager (ScheduledJob ['.$scheduledJob['id'].']): Unsupported CRON expression ['.$scheduling.']');
$GLOBALS['log']->error('CronManager (ScheduledJob ['.$scheduledJob->id.']): Unsupported CRON expression ['.$scheduling.']');
continue;
}
$existingJob = $this->getCronJob()->getJobByScheduledJob($scheduledJob['id'], $nextDate);
$existingJob = $this->getCronJobUtil()->getJobByScheduledJob($scheduledJob->id, $nextDate);
if ($existingJob) continue;
$className = $this->getScheduledJobUtil()->get($scheduledJob['job']);
$className = $this->getScheduledJobUtil()->get($scheduledJob->get('job'));
if ($className) {
if (method_exists($className, 'prepare')) {
$implementation = new $className($this->container);
@@ -301,24 +301,18 @@ class CronManager
}
}
if (in_array($scheduledJob['id'], $runningScheduledJobIdList)) {
if (in_array($scheduledJob->id, $runningScheduledJobIdList)) {
continue;
}
$jobEntity = $this->getEntityManager()->getEntity('Job');
$jobEntity->set(array(
'name' => $scheduledJob['name'],
'name' => $scheduledJob->get('name'),
'status' => self::PENDING,
'scheduledJobId' => $scheduledJob['id'],
'executeTime' => $nextDate,
'method' => $scheduledJob['job']
'scheduledJobId' => $scheduledJob->id,
'executeTime' => $nextDate
));
$this->getEntityManager()->saveEntity($jobEntity);
$createdJobIdList[] = $jobEntity->id;
}
return $createdJobIdList;
}
}
+28 -42
View File
@@ -74,18 +74,39 @@ class Job
$jobConfigs = $this->getConfig()->get('cron');
$limit = !empty($jobConfigs['maxJobNumber']) ? intval($jobConfigs['maxJobNumber']) : 0;
$jobList = $this->getJobList(CronManager::PENDING, $limit);
$selectParams = [
'select' => [
'id',
'scheduledJobId',
'scheduledJobJob',
'executeTime',
'targetId',
'targetType',
'methodName',
'method', // TODO remove deprecated
'serviceName'
],
'whereClause' => [
'status' => 'Pending',
'executeTime<=' => date('Y-m-d H:i:s')
],
'orderBy' => 'executeTime'
];
if ($limit) {
$selectParams['offset'] = 0;
$selectParams['limit'] = $limit;
}
$jobList = $this->getEntityManager()->getRepository('Job')->find($selectParams);
$runningScheduledJobIdList = $this->getRunningScheduledJobIdList();
$list = [];
foreach ($jobList as $row) {
if (!in_array($row['scheduled_job_id'], $runningScheduledJobIdList)) {
$list[] = $row;
}
$actualJobList = [];
foreach ($jobList as $job) {
if ($job->get('scheduledJobId') && in_array($job->get('scheduledJobId'), $runningScheduledJobIdList)) continue;
$actualJobList[] = $job;
}
return $list;
return $actualJobList;
}
public function getRunningScheduledJobIdList()
@@ -114,41 +135,6 @@ class Job
return $list;
}
/**
* Get job list, which execution date in jobPeriod time
*
* @param string $status
* @param int $limit
*
* @return array
*/
public function getJobList($status = CronManager::PENDING, $limit = null)
{
$currentTime = time();
$pdo = $this->getEntityManager()->getPDO();
$query = "
SELECT * FROM job
WHERE
`status` = " . $pdo->quote($status) . "
AND execute_time <= '".date('Y-m-d H:i:s', $currentTime)."'
AND deleted = 0
ORDER BY execute_time ASC
";
if ($limit) {
$query .= " LIMIT " . $limit ;
}
$sth = $pdo->prepare($query);
$sth->execute();
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
return $rows;
}
/**
* Get Jobs by ScheduledJobId and date
*
@@ -55,31 +55,17 @@ class ScheduledJob
}
/**
* Get active Scheduler Jobs
* Get active Scheduler Job List
*
* @return array
* @return EntityCollection
*/
public function getActiveScheduledJobList()
{
$query = "
SELECT * FROM scheduled_job
WHERE
`status` = 'Active' AND
deleted = 0
";
$pdo = $this->getEntityManager()->getPDO();
$sth = $pdo->prepare($query);
$sth->execute();
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
$list = array();
foreach ($rows as $row) {
$list[] = $row;
}
return $list;
return $this->getEntityManager()->getRepository('ScheduledJob')->select([
'id', 'scheduling', 'job', 'name'
])->where([
'status' => 'Active'
])->find();
}
/**
@@ -51,12 +51,12 @@ class AssignmentEmailNotification extends \Espo\Core\Hooks\Base
$job = $this->getEntityManager()->getEntity('Job');
$job->set(array(
'serviceName' => 'EmailNotification',
'method' => 'notifyAboutAssignmentJob',
'methodName' => 'notifyAboutAssignmentJob',
'data' => json_encode(array(
'userId' => $userId,
'assignerUserId' => $this->getUser()->id,
'entityId' => $entity->id,
'entityType' => $entity->getEntityName()
'entityType' => $entity->getEntityType()
)),
'executeTime' => date('Y-m-d H:i:s'),
));
@@ -64,6 +64,4 @@ class AssignmentEmailNotification extends \Espo\Core\Hooks\Base
}
}
}
}
+2 -4
View File
@@ -238,7 +238,7 @@ class Stream extends \Espo\Core\Hooks\Base
$job = $this->getEntityManager()->getEntity('Job');
$job->set(array(
'serviceName' => 'Stream',
'method' => 'afterRecordCreatedJob',
'methodName' => 'afterRecordCreatedJob',
'data' => array(
'userIdList' => $autofollowUserIdList,
'entityType' => $entity->getEntityType(),
@@ -247,7 +247,6 @@ class Stream extends \Espo\Core\Hooks\Base
));
$this->getEntityManager()->saveEntity($job);
}
} else {
if (empty($options['noStream']) && empty($options['silent'])) {
if ($entity->isFieldChanged('assignedUserId')) {
@@ -297,7 +296,7 @@ class Stream extends \Espo\Core\Hooks\Base
$job = $this->getEntityManager()->getEntity('Job');
$job->set(array(
'serviceName' => 'Stream',
'method' => 'controlFollowersJob',
'methodName' => 'controlFollowersJob',
'data' => array(
'entityType' => $entity->getEntityType(),
'entityId' => $entity->id
@@ -306,7 +305,6 @@ class Stream extends \Espo\Core\Hooks\Base
$this->getEntityManager()->saveEntity($job);
}
}
}
if ($entity->isNew() && empty($options['noStream']) && empty($options['silent']) && $this->getMetadata()->get(['scopes', $entityType, 'object'])) {
@@ -58,14 +58,14 @@ class CheckEmailAccounts extends \Espo\Core\Jobs\Base
return true;
}
public function prepare($data, $executeTime)
public function prepare($scheduledJob, $executeTime)
{
$collection = $this->getEntityManager()->getRepository('EmailAccount')->where(array(
'status' => 'Active'
))->find();
foreach ($collection as $entity) {
$running = $this->getEntityManager()->getRepository('Job')->where(array(
'scheduledJobId' => $data['id'],
'scheduledJobId' => $scheduledJob->id,
'status' => 'Running',
'targetType' => 'EmailAccount',
'targetId' => $entity->id
@@ -73,21 +73,18 @@ class CheckEmailAccounts extends \Espo\Core\Jobs\Base
if ($running) continue;
$countPending = $this->getEntityManager()->getRepository('Job')->where(array(
'scheduledJobId' => $data['id'],
'scheduledJobId' => $scheduledJob->id,
'status' => 'Pending',
'targetType' => 'EmailAccount',
'targetId' => $entity->id
))->count();
if ($countPending > 1) continue;
$job = $this->getEntityManager()->getEntity('Job');
$jobEntity = $this->getEntityManager()->getEntity('Job');
$jobEntity->set(array(
'name' => $data['name'],
'scheduledJobId' => $data['id'],
'name' => $scheduledJob->get('name'),
'scheduledJobId' => $scheduledJob->id,
'executeTime' => $executeTime,
'method' => 'CheckEmailAccounts',
'targetType' => 'EmailAccount',
'targetId' => $entity->id
));
@@ -97,4 +94,3 @@ class CheckEmailAccounts extends \Espo\Core\Jobs\Base
return true;
}
}
@@ -5,8 +5,10 @@
"attempts": "Attempts Left",
"failedAttempts": "Failed Attempts",
"serviceName": "Service",
"method": "Method",
"method": "Method (deprecated)",
"methodName": "Method",
"scheduledJob": "Scheduled Job",
"scheduledJobJob": "Scheduled Job Name",
"data": "Data"
},
"options": {
@@ -13,7 +13,7 @@
"rows":[
[{"name":"scheduledJob"}, false],
[{"name":"serviceName"}, false],
[{"name":"method"}, false],
[{"name":"methodName"}, false],
[{"name": "data"}]
]
}
@@ -24,12 +24,21 @@
"required": true,
"maxLength":100
},
"methodName": {
"type": "varchar",
"maxLength": 100
},
"data": {
"type": "jsonObject"
},
"scheduledJob": {
"type": "link"
},
"scheduledJobJob": {
"type": "foreign",
"link": "scheduledJob",
"field": "job"
},
"attempts": {
"type": "int"
},
@@ -62,7 +71,7 @@
"collection": {
"sortBy": "createdAt",
"asc": false,
"textFilterFields": ["name", "method", "serviceName"]
"textFilterFields": ["name", "methodName", "serviceName", "scheduledJobName"]
},
"indexes": {
"executeTime": {
@@ -94,15 +94,15 @@ class EmailNotification extends \Espo\Core\Services\Base
public function notifyAboutAssignmentJob($data)
{
if (empty($data['userId'])) return;
if (empty($data['assignerUserId'])) return;
if (empty($data['entityId'])) return;
if (empty($data['entityType'])) return;
if (empty($data->userId)) return;
if (empty($data->assignerUserId)) return;
if (empty($data->entityId)) return;
if (empty($data->entityType)) return;
$userId = $data['userId'];
$assignerUserId = $data['assignerUserId'];
$entityId = $data['entityId'];
$entityType = $data['entityType'];
$userId = $data->userId;
$assignerUserId = $data->assignerUserId;
$entityId = $data->entityId;
$entityType = $data->entityType;
$user = $this->getEntityManager()->getEntity('User', $userId);
+6 -6
View File
@@ -277,14 +277,14 @@ class Import extends \Espo\Services\Record
public function runIdleImport($data)
{
$entityType = $data['entityType'];
$entityType = $data->entityType;
$params = json_decode(json_encode($data['params']), true);
$params = json_decode(json_encode($data->params), true);
$importFieldList = $data['importFieldList'];
$attachmentId = $data['attachmentId'];
$importFieldList = $data->importFieldList;
$attachmentId = $data->attachmentId;
$importId = $data['importId'];
$importId = $data->importId;
$this->import($entityType, $importFieldList, $attachmentId, $params, $importId);
}
@@ -332,7 +332,7 @@ class Import extends \Espo\Services\Record
$job = $this->getEntityManager()->getEntity('Job');
$job->set(array(
'serviceName' => 'Import',
'method' => 'runIdleImport',
'methodName' => 'runIdleImport',
'data' => array(
'entityType' => $scope,
'params' => $params,
+6 -8
View File
@@ -123,12 +123,12 @@ class Stream extends \Espo\Core\Services\Base
if (empty($data)) {
return;
}
if (empty($data['entityId']) || empty($data['entityType']) || empty($data['userIdList'])) {
if (empty($data->entityId) || empty($data->entityType) || empty($data->userIdList)) {
return;
}
$userIdList = $data['userIdList'];
$entityType = $data['entityType'];
$entityId = $data['entityId'];
$userIdList = $data->userIdList;
$entityType = $data->entityType;
$entityId = $data->entityId;
$entity = $this->getEntityManager()->getEntity($entityType, $entityId);
if (!$entity) {
@@ -1119,10 +1119,10 @@ class Stream extends \Espo\Core\Services\Base
if (empty($data)) {
return;
}
if (empty($data['entityId']) || empty($data['entityType'])) {
if (empty($data->entityId) || empty($data->entityType)) {
return;
}
$entity = $this->getEntityManager()->getEntity($data['entityType'], $data['entityId']);
$entity = $this->getEntityManager()->getEntity($data->entityType, $data->entityId);
if (!$entity) return;
$idList = $this->getEntityFolowerIdList($entity);
@@ -1144,7 +1144,5 @@ class Stream extends \Espo\Core\Services\Base
}
}
}
}
}
+7 -7
View File
@@ -178,11 +178,11 @@ class User extends Record
$job->set(array(
'serviceName' => 'User',
'method' => 'removeChangePasswordRequestJob',
'data' => json_encode(array(
'id' => $passwordChangeRequest->id,
)),
'executeTime' => $dt->format('Y-m-d H:i:s') ,
'methodName' => 'removeChangePasswordRequestJob',
'data' => [
'id' => $passwordChangeRequest->id
],
'executeTime' => $dt->format('Y-m-d H:i:s')
));
$this->getEntityManager()->saveEntity($job);
@@ -192,10 +192,10 @@ class User extends Record
public function removeChangePasswordRequestJob($data)
{
if (empty($data['id'])) {
if (empty($data->id)) {
return;
}
$id = $data['id'];
$id = $data->id;
$p = $this->getEntityManager()->getEntity('PasswordChangeRequest', $id);
if ($p) {