Skip to content

Commit

Permalink
Merge pull request #1415 from siemens/feat/api/jobStatusAndETA
Browse files Browse the repository at this point in the history
feat(api): Return job's ETA and status
      tested by : anupam.ghosh@siemens.com
      reviewed by : anupam.ghosh@siemens.com
  • Loading branch information
ag4ums committed Sep 14, 2019
2 parents fc1b3ce + 5a9a341 commit 53d13ec
Show file tree
Hide file tree
Showing 7 changed files with 502 additions and 26 deletions.
3 changes: 2 additions & 1 deletion src/lib/php/services.xml.in
Expand Up @@ -191,7 +191,8 @@ without any warranty.
<argument type="service" id="dao.folder"/>
<argument type="service" id="helper.dbHelper"/>
<argument type="service" id="helper.authHelper"/>
<argument type="service" id="logger"/>
<argument type="service" id="dao.job"/>
<argument type="service" id="dao.show_jobs"/>
</service>
</services>
</container>
197 changes: 192 additions & 5 deletions src/www/ui/api/Controllers/JobController.php
Expand Up @@ -31,13 +31,34 @@
use Fossology\UI\Api\Models\Decider;
use Fossology\UI\Api\Models\Reuser;
use Fossology\UI\Api\Models\ScanOptions;
use Fossology\UI\Api\Models\Job;

/**
* @class JobController
* @brief Controller for Job model
*/
class JobController extends RestController
{
/**
* Get query parameter name for upload filtering
*/
const UPLOAD_PARAM = "upload";
/**
* Job completed successfully
*/
const JOB_COMPLETED = 0x1 << 1;
/**
* Job started by scheduler
*/
const JOB_STARTED = 0x1 << 2;
/**
* Job waiting to be queued
*/
const JOB_QUEUED = 0x1 << 3;
/**
* Job failed
*/
const JOB_FAILED = 0x1 << 4;
/**
* Get all jobs by a user
*
Expand All @@ -48,16 +69,25 @@ class JobController extends RestController
*/
public function getJobs($request, $response, $args)
{
$query = $request->getQueryParams();

$limit = 0;
$page = 1;
if ($request->hasHeader('limit')) {
$limit = $request->getHeaderLine('limit');
if (isset($limit) && (! is_numeric($limit) || $limit < 0)) {
$page = $request->getHeaderLine('page');
if (empty($page)) {
$page = 1;
}
if ((isset($limit) && (! is_numeric($limit) || $limit < 0)) ||
(! is_numeric($page) || $page < 1)) {
$returnVal = new Info(400,
"Limit cannot be smaller than 1 and has to be numeric!",
"Limit and page cannot be smaller than 1 and has to be numeric!",
InfoType::ERROR);
return $response->withJson($returnVal->getArray(), $returnVal->getCode());
}
}

$id = null;
if (isset($args['id'])) {
$id = intval($args['id']);
Expand All @@ -67,11 +97,19 @@ public function getJobs($request, $response, $args)
return $response->withJson($returnVal->getArray(), $returnVal->getCode());
}
}
$jobs = $this->dbHelper->getJobs($limit, $id);

if ($id !== null) {
$jobs = $jobs[0];
/* If the ID is passed, don't check for upload */
return $this->getAllResults($id, $response, $limit, $page);
}

if (array_key_exists(self::UPLOAD_PARAM, $query)) {
/* If the upload is passed, filter accordingly */
return $this->getFilteredResults(intval($query[self::UPLOAD_PARAM]),
$response, $limit, $page);
} else {
return $this->getAllResults($id, $response, $limit, $page);
}
return $response->withJson($jobs, 200);
}

/**
Expand Down Expand Up @@ -115,4 +153,153 @@ public function createJob($request, $response, $args)
return $response->withJson($error->getArray(), $error->getCode());
}
}

/**
* Get all jobs for the current user.
*
* @param integer|null $id Specific job id or null for all jobs
* @param ResponseInterface $response Response object
* @param integer $limit Limit of jobs per page
* @param integer $page Page number required
* @return ResponseInterface
*/
private function getAllResults($id, $response, $limit, $page)
{
list($jobs, $count) = $this->dbHelper->getJobs($id, $limit, $page);
$finalJobs = [];
foreach ($jobs as $job) {
$this->updateEtaAndStatus($job);
$finalJobs[] = $job->getArray();
}
if ($id !== null) {
$finalJobs = $finalJobs[0];
}
return $response->withHeader("X-Total-Pages", $count)->withJson($finalJobs, 200);
}

/**
* Get all jobs for the given upload.
*
* @param integer $uploadId Upload id to be filtered
* @param ResponseInterface $response Response object
* @param integer $limit Limit of jobs per page
* @param integer $page Page number required
* @return ResponseInterface
*/
private function getFilteredResults($uploadId, $response, $limit, $page)
{
if (! $this->dbHelper->doesIdExist("upload", "upload_pk", $uploadId)) {
$returnVal = new Info(404, "Upload id " . $uploadId . " doesn't exist",
InfoType::ERROR);
return $response->withJson($returnVal->getArray(), $returnVal->getCode());
}
list($jobs, $count) = $this->dbHelper->getJobs(null, $limit, $page, $uploadId);
$finalJobs = [];
foreach ($jobs as $job) {
$this->updateEtaAndStatus($job);
$finalJobs[] = $job->getArray();
}
return $response->withHeader("X-Total-Pages", $count)->withJson($finalJobs, 200);
}

/**
* Update the ETA and status for the given job
*
* @param[in,out] Job $job The job to be updated
*/
private function updateEtaAndStatus(&$job)
{
$jobDao = $this->restHelper->getJobDao();

$eta = 0;
$status = "";
$jobqueue = [];

/* Check if the job has no upload like Maintenance job */
if (empty($job->getUploadId())) {
$sql = "SELECT jq_pk, jq_end_bits from jobqueue WHERE jq_job_fk = $1;";
$statement = __METHOD__ . ".getJqpk";
$rows = $this->dbHelper->getDbManager()->getRows($sql, [$job->getId()],
$statement);
if (count($rows) > 0) {
$jobqueue[$rows[0]['jq_pk']] = $rows[0]['jq_end_bits'];
}
} else {
$jobqueue = $jobDao->getAllJobStatus($job->getUploadId(),
$job->getUserId(), $job->getGroupId());
}

$job->setEta($this->getUploadEtaInSeconds($job->getId(),
$job->getUploadId()));

$job->setStatus($this->getJobStatus(array_keys($jobqueue)));
}

/**
* Get the ETA in seconds for the upload.
*
* @param integer $jobId The job ID for which the ETA is required
* @param integer $uploadId Upload for which the ETA is required
* @return integer ETA in seconds (0 if job already finished)
*/
private function getUploadEtaInSeconds($jobId, $uploadId)
{
$showJobDao = $this->restHelper->getShowJobDao();
$eta = $showJobDao->getEstimatedTime($jobId, '', 0, $uploadId);
$eta = explode(":", $eta);
if (count($eta) > 1) {
$eta = ($eta[0] * 3600) + ($eta[1] * 60) + ($eta[2]);
} else {
$eta = 0;
}
return $eta;
}

/**
* Get the job status based on jobqueue.
*
* @param array $jobqueue The job queue with job id as values
* @return string Job status (Completed, Processing, Queued or Failed)
*/
private function getJobStatus($jobqueue)
{
$showJobDao = $this->restHelper->getShowJobDao();
$jobStatus = 0;
/* Check each job in queue */
foreach ($jobqueue as $jobId) {
$jobInfo = $showJobDao->getDataForASingleJob($jobId);
$endtext = $jobInfo['jq_endtext'];
switch ($endtext) {
case 'Completed':
$jobStatus |= self::JOB_COMPLETED;
break;
case 'Started':
case 'Restarted':
case 'Paused':
$jobStatus |= self::JOB_STARTED;
break;
default:
if (empty($jobInfo['jq_endtime'])) {
$jobStatus |= self::JOB_QUEUED;
} else {
$jobStatus |= self::JOB_FAILED;
}
}
}

$jobStatusString = "";
if ($jobStatus & self::JOB_STARTED) {
/* If at least one job is started, set status as processing */
$jobStatusString = "Processing";
} else if ($jobStatus & self::JOB_QUEUED) {
$jobStatusString = "Queued";
} else if ($jobStatus & self::JOB_FAILED) {
/* If at least one job is failed, set status as failed */
$jobStatusString = "Failed";
} else {
/* If everything completed successfully, set status as completed */
$jobStatusString = "Completed";
}
return $jobStatusString;
}
}
65 changes: 52 additions & 13 deletions src/www/ui/api/Helper/DbHelper.php
Expand Up @@ -190,31 +190,70 @@ public function getUsers($id = null)
*
* If a limit is passed, the results are trimmed. If an ID is passed, the
* information for the given id is only retrieved.
* @param integer $limit Set to limit the result length
* @param integer $id Set to get information of only given job id
* @return Job[][] Jobs as an associative array
*
* @param integer $id Set to get information of only given job id
* @param integer $limit Set to limit the result length
* @param integer $page Page number required
* @param integer $uploadId Upload ID to be filtered
* @return array[] List of jobs at first index and total number of pages at
* second.
*/
public function getJobs($limit = 0, $id = null)
public function getJobs($id = null, $limit = 0, $page = 1, $uploadId = null)
{
$jobSQL = "SELECT job_pk, job_queued, job_name, job_upload_fk," .
" job_user_fk, job_group_fk FROM job";
$totalJobSql = "SELECT count(*) AS cnt FROM job";

$filter = "";
$pagination = "";

$params = [];
$statement = __METHOD__ . ".getJobs";
$countStatement = __METHOD__ . ".getJobCount";
if ($id == null) {
$jobSQL = "SELECT job_pk, job_queued, job_name, job_upload_fk, job_user_fk, job_group_fk FROM job";
if ($uploadId !== null) {
$params[] = $uploadId;
$filter = "WHERE job_upload_fk = $" . count($params);
$statement .= ".withUploadFilter";
$countStatement .= ".withUploadFilter";
}
} else {
$jobSQL = "SELECT job_pk, job_queued, job_name, job_upload_fk, job_user_fk, job_group_fk
FROM job WHERE job_pk=" . pg_escape_string($id);
$params[] = $id;
$filter = "WHERE job_pk = $" . count($params);
$statement .= ".withJobFilter";
$countStatement .= ".withJobFilter";
}

$result = $this->dbManager->getSingleRow("$totalJobSql $filter;", $params,
$countStatement);

$totalResult = $result['cnt'];

$offset = ($page - 1) * $limit;
if ($limit > 0) {
$jobSQL .= " LIMIT " . pg_escape_string($limit);
$params[] = $limit;
$pagination = "LIMIT $" . count($params);
$params[] = $offset;
$pagination .= " OFFSET $" . count($params);
$statement .= ".withLimit";
$totalResult = floor($totalResult / $limit) + 1;
} else {
$totalResult = 1;
}

$jobs = [];
$result = $this->dbManager->getRows($jobSQL);
$result = $this->dbManager->getRows("$jobSQL $filter $pagination;", $params,
$statement);
foreach ($result as $row) {
$job = new Job($row["job_pk"], $row["job_name"], $row["job_queued"],
$row["job_upload_fk"], $row["job_user_fk"], $row["job_group_fk"]);
$jobs[] = $job->getArray();
$job = new Job($row["job_pk"]);
$job->setName($row["job_name"]);
$job->setQueueDate($row["job_queued"]);
$job->setUploadId($row["job_upload_fk"]);
$job->setUserId($row["job_user_fk"]);
$job->setGroupId($row["job_group_fk"]);
$jobs[] = $job;
}
return $jobs;
return [$jobs, $totalResult];
}

/**
Expand Down

0 comments on commit 53d13ec

Please sign in to comment.