Skip to content

Commit 542d4da

Browse files
ernjvryadvr
authored andcommitted
asyncjobs: add endtime to async jobs (#2739)
There is currently no functional mechanism that captures or persists the end time of when an asynchronous job has finished. As a result, users are not able to do any reporting about the duration of various asynchronous jobs in Cloudstack. Link to FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Add+End+Time+To+Asynchronous+Jobs
1 parent 4434901 commit 542d4da

14 files changed

Lines changed: 286 additions & 29 deletions

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ env:
4242
- TESTS="smoke/test_accounts
4343
smoke/test_affinity_groups
4444
smoke/test_affinity_groups_projects
45+
smoke/test_async_job
4546
smoke/test_deploy_vgpu_enabled_vm
4647
smoke/test_deploy_vm_iso
4748
smoke/test_deploy_vm_root_resize

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ public class ApiConstants {
549549
public static final String IPSEC_PSK = "ipsecpsk";
550550
public static final String GUEST_IP = "guestip";
551551
public static final String REMOVED = "removed";
552+
public static final String COMPLETED = "completed";
552553
public static final String IKE_POLICY = "ikepolicy";
553554
public static final String ESP_POLICY = "esppolicy";
554555
public static final String IKE_LIFETIME = "ikelifetime";

api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ public class AsyncJobResponse extends BaseResponse {
7575
@Param(description = " the created date of the job")
7676
private Date created;
7777

78+
@SerializedName(ApiConstants.COMPLETED)
79+
@Param(description = " the completed date of the job")
80+
private Date removed;
81+
7882
public void setAccountId(String accountId) {
7983
this.accountId = accountId;
8084
}
@@ -119,4 +123,8 @@ public void setJobInstanceId(String jobInstanceId) {
119123
public void setCreated(Date created) {
120124
this.created = created;
121125
}
126+
127+
public void setRemoved(final Date removed) {
128+
this.removed = removed;
129+
}
122130
}

api/src/main/java/org/apache/cloudstack/jobs/JobInfo.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public boolean done() {
6868

6969
Date getCreated();
7070

71+
Date getRemoved();
72+
7173
Date getLastUpdated();
7274

7375
Date getLastPolled();

engine/schema/src/main/resources/META-INF/db/schema-41110to41200.sql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@ ALTER TABLE `vlan` CHANGE `description` `ip4_range` varchar(255);
3232
-- We are only adding the permission to the default rules. Any custom rule must be configured by the root admin.
3333
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'moveNetworkAclItem', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule;
3434
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'moveNetworkAclItem', 'ALLOW', 302) ON DUPLICATE KEY UPDATE rule=rule;
35-
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'moveNetworkAclItem', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule;
35+
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'moveNetworkAclItem', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule;
36+
37+
UPDATE `cloud`.`async_job` SET `removed` = now() WHERE `removed` IS NULL;

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.cloud.utils.db.GenericDao;
2525

2626
public interface AsyncJobDao extends GenericDao<AsyncJobVO, Long> {
27+
2728
AsyncJobVO findInstancePendingAsyncJob(String instanceType, long instanceId);
2829

2930
List<AsyncJobVO> findInstancePendingAsyncJobs(String instanceType, Long accountId);

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Date;
2222
import java.util.List;
2323

24+
import org.apache.cloudstack.api.ApiConstants;
2425
import org.apache.log4j.Logger;
2526

2627
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
@@ -71,7 +72,7 @@ public AsyncJobDaoImpl() {
7172
expiringUnfinishedAsyncJobSearch.done();
7273

7374
expiringCompletedAsyncJobSearch = createSearchBuilder();
74-
expiringCompletedAsyncJobSearch.and("created", expiringCompletedAsyncJobSearch.entity().getCreated(), SearchCriteria.Op.LTEQ);
75+
expiringCompletedAsyncJobSearch.and(ApiConstants.REMOVED, expiringCompletedAsyncJobSearch.entity().getRemoved(), SearchCriteria.Op.LTEQ);
7576
expiringCompletedAsyncJobSearch.and("completeMsId", expiringCompletedAsyncJobSearch.entity().getCompleteMsid(), SearchCriteria.Op.NNULL);
7677
expiringCompletedAsyncJobSearch.and("jobStatus", expiringCompletedAsyncJobSearch.entity().getStatus(), SearchCriteria.Op.NEQ);
7778
expiringCompletedAsyncJobSearch.done();
@@ -168,11 +169,11 @@ public List<AsyncJobVO> getExpiredUnfinishedJobs(Date cutTime, int limit) {
168169
}
169170

170171
@Override
171-
public List<AsyncJobVO> getExpiredCompletedJobs(Date cutTime, int limit) {
172-
SearchCriteria<AsyncJobVO> sc = expiringCompletedAsyncJobSearch.create();
173-
sc.setParameters("created", cutTime);
172+
public List<AsyncJobVO> getExpiredCompletedJobs(final Date cutTime, final int limit) {
173+
final SearchCriteria<AsyncJobVO> sc = expiringCompletedAsyncJobSearch.create();
174+
sc.setParameters(ApiConstants.REMOVED, cutTime);
174175
sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS);
175-
Filter filter = new Filter(AsyncJobVO.class, "created", true, 0L, (long)limit);
176+
final Filter filter = new Filter(AsyncJobVO.class, ApiConstants.REMOVED, true, 0L, (long)limit);
176177
return listIncludingRemovedBy(sc, filter);
177178
}
178179

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public ConfigKey<?>[] getConfigKeys() {
161161

162162
@Override
163163
public AsyncJobVO getAsyncJob(long jobId) {
164-
return _jobDao.findById(jobId);
164+
return _jobDao.findByIdIncludingRemoved(jobId);
165165
}
166166

167167
@Override
@@ -286,9 +286,9 @@ public void completeAsyncJob(final long jobId, final Status jobStatus, final int
286286
if (s_logger.isDebugEnabled()) {
287287
s_logger.debug("Wake up jobs related to job-" + jobId);
288288
}
289-
List<Long> wakeupList = Transaction.execute(new TransactionCallback<List<Long>>() {
289+
final List<Long> wakeupList = Transaction.execute(new TransactionCallback<List<Long>>() {
290290
@Override
291-
public List<Long> doInTransaction(TransactionStatus status) {
291+
public List<Long> doInTransaction(final TransactionStatus status) {
292292
if (s_logger.isDebugEnabled()) {
293293
s_logger.debug("Update db status for job-" + jobId);
294294
}
@@ -302,14 +302,16 @@ public List<Long> doInTransaction(TransactionStatus status) {
302302
job.setResult(null);
303303
}
304304

305-
job.setLastUpdated(DateUtil.currentGMTTime());
305+
final Date currentGMTTime = DateUtil.currentGMTTime();
306+
job.setLastUpdated(currentGMTTime);
307+
job.setRemoved(currentGMTTime);
306308
job.setExecutingMsid(null);
307309
_jobDao.update(jobId, job);
308310

309311
if (s_logger.isDebugEnabled()) {
310312
s_logger.debug("Wake up jobs joined with job-" + jobId + " and disjoin all subjobs created from job- " + jobId);
311313
}
312-
List<Long> wakeupList = wakeupByJoinedJobCompletion(jobId);
314+
final List<Long> wakeupList = wakeupByJoinedJobCompletion(jobId);
313315
_joinMapDao.disjoinAllJobs(jobId);
314316

315317
// purge the job sync item from queue
@@ -445,8 +447,8 @@ public void syncAsyncJobExecution(AsyncJob job, String syncObjType, long syncObj
445447
}
446448

447449
@Override
448-
public AsyncJob queryJob(long jobId, boolean updatePollTime) {
449-
AsyncJobVO job = _jobDao.findById(jobId);
450+
public AsyncJob queryJob(final long jobId, final boolean updatePollTime) {
451+
final AsyncJobVO job = _jobDao.findByIdIncludingRemoved(jobId);
450452

451453
if (updatePollTime) {
452454
job.setLastPolled(DateUtil.currentGMTTime());
@@ -1025,21 +1027,24 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
10251027
// purge sync queue item running on this ms node
10261028
_queueMgr.cleanupActiveQueueItems(msid, true);
10271029
// reset job status for all jobs running on this ms node
1028-
List<AsyncJobVO> jobs = _jobDao.getResetJobs(msid);
1029-
for (AsyncJobVO job : jobs) {
1030+
final List<AsyncJobVO> jobs = _jobDao.getResetJobs(msid);
1031+
for (final AsyncJobVO job : jobs) {
10301032
if (s_logger.isDebugEnabled()) {
10311033
s_logger.debug("Cancel left-over job-" + job.getId());
10321034
}
10331035
job.setStatus(JobInfo.Status.FAILED);
10341036
job.setResultCode(ApiErrorCode.INTERNAL_ERROR.getHttpCode());
10351037
job.setResult("job cancelled because of management server restart or shutdown");
10361038
job.setCompleteMsid(msid);
1039+
final Date currentGMTTime = DateUtil.currentGMTTime();
1040+
job.setLastUpdated(currentGMTTime);
1041+
job.setRemoved(currentGMTTime);
10371042
_jobDao.update(job.getId(), job);
10381043
if (s_logger.isDebugEnabled()) {
10391044
s_logger.debug("Purge queue item for cancelled job-" + job.getId());
10401045
}
10411046
_queueMgr.purgeAsyncJobQueueItemId(job.getId());
1042-
if (job.getInstanceType().equals(ApiCommandJobType.Volume.toString())) {
1047+
if (ApiCommandJobType.Volume.toString().equals(job.getInstanceType())) {
10431048

10441049
try {
10451050
_volumeDetailsDao.removeDetail(job.getInstanceId(), "SNAPSHOT_ID");
@@ -1049,8 +1054,8 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
10491054
}
10501055
}
10511056
}
1052-
List<SnapshotDetailsVO> snapshotList = _snapshotDetailsDao.findDetails(AsyncJob.Constants.MS_ID, Long.toString(msid), false);
1053-
for (SnapshotDetailsVO snapshotDetailsVO : snapshotList) {
1057+
final List<SnapshotDetailsVO> snapshotList = _snapshotDetailsDao.findDetails(AsyncJob.Constants.MS_ID, Long.toString(msid), false);
1058+
for (final SnapshotDetailsVO snapshotDetailsVO : snapshotList) {
10541059
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotDetailsVO.getResourceId(), DataStoreRole.Primary);
10551060
snapshotSrv.processEventOnSnapshotObject(snapshot, Snapshot.Event.OperationFailed);
10561061
_snapshotDetailsDao.removeDetail(snapshotDetailsVO.getResourceId(), AsyncJob.Constants.MS_ID);

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobVO.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,15 @@ public void setUuid(String uuid) {
372372
this.uuid = uuid;
373373
}
374374

375+
@Override
376+
public Date getRemoved() {
377+
return removed;
378+
}
379+
380+
public void setRemoved(final Date removed) {
381+
this.removed = removed;
382+
}
383+
375384
@Override
376385
public String toString() {
377386
StringBuffer sb = new StringBuffer();
@@ -392,6 +401,7 @@ public String toString() {
392401
sb.append(", lastUpdated: ").append(getLastUpdated());
393402
sb.append(", lastPolled: ").append(getLastPolled());
394403
sb.append(", created: ").append(getCreated());
404+
sb.append(", removed: ").append(getRemoved());
395405
sb.append("}");
396406
return sb.toString();
397407
}

server/src/main/java/com/cloud/api/ApiResponseHelper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,16 +1808,16 @@ public TemplatePermissionsResponse createTemplatePermissionsResponse(ResponseVie
18081808
}
18091809

18101810
@Override
1811-
public AsyncJobResponse queryJobResult(QueryAsyncJobResultCmd cmd) {
1812-
Account caller = CallContext.current().getCallingAccount();
1811+
public AsyncJobResponse queryJobResult(final QueryAsyncJobResultCmd cmd) {
1812+
final Account caller = CallContext.current().getCallingAccount();
18131813

1814-
AsyncJob job = _entityMgr.findById(AsyncJob.class, cmd.getId());
1814+
final AsyncJob job = _entityMgr.findByIdIncludingRemoved(AsyncJob.class, cmd.getId());
18151815
if (job == null) {
18161816
throw new InvalidParameterValueException("Unable to find a job by id " + cmd.getId());
18171817
}
18181818

1819-
User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId());
1820-
Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId());
1819+
final User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId());
1820+
final Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId());
18211821

18221822
//check permissions
18231823
if (_accountMgr.isNormalUser(caller.getId())) {

0 commit comments

Comments
 (0)