This is an automated email from the ASF dual-hosted git repository.
lahirujayathilake pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata.git
The following commit(s) were added to refs/heads/master by this push:
new a88a48afab support AWS resource cleanup when walltime hits
a88a48afab is described below
commit a88a48afabed904d3e6e4949f01b718773ab8218
Author: lahiruj <[email protected]>
AuthorDate: Fri Jul 25 15:56:10 2025 -0400
support AWS resource cleanup when walltime hits
---
.../helix/impl/participant/GlobalParticipant.java | 1 +
.../airavata/helix/impl/task/AWSTaskFactory.java | 4 +-
.../helix/impl/task/aws/AWSCompletingTask.java | 49 ++++++++++++++++++++++
.../task/submission/config/GroovyMapBuilder.java | 3 ++
.../impl/task/submission/config/GroovyMapData.java | 22 ++++++++++
.../main/resources/templates/CLOUD_Groovy.template | 25 +++++++++--
6 files changed, 99 insertions(+), 5 deletions(-)
diff --git
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/participant/GlobalParticipant.java
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/participant/GlobalParticipant.java
index 50a965d603..3cb6be524c 100644
---
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/participant/GlobalParticipant.java
+++
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/participant/GlobalParticipant.java
@@ -52,6 +52,7 @@ public class GlobalParticipant extends
HelixParticipant<AbstractTask> {
"org.apache.airavata.helix.impl.task.aws.CreateEC2InstanceTask",
"org.apache.airavata.helix.impl.task.aws.NoOperationTask",
"org.apache.airavata.helix.impl.task.aws.AWSJobSubmissionTask",
+ "org.apache.airavata.helix.impl.task.aws.AWSCompletingTask",
};
@SuppressWarnings("WeakerAccess")
diff --git
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
index 9f61ccba60..d57c75efe5 100644
---
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
+++
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/AWSTaskFactory.java
@@ -19,10 +19,10 @@
*/
package org.apache.airavata.helix.impl.task;
+import org.apache.airavata.helix.impl.task.aws.AWSCompletingTask;
import org.apache.airavata.helix.impl.task.aws.AWSJobSubmissionTask;
import org.apache.airavata.helix.impl.task.aws.CreateEC2InstanceTask;
import org.apache.airavata.helix.impl.task.aws.NoOperationTask;
-import org.apache.airavata.helix.impl.task.completing.CompletingTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,7 +63,7 @@ public class AWSTaskFactory implements HelixTaskFactory {
@Override
public AiravataTask createCompletingTask(String processId) {
- return new CompletingTask();
+ return new AWSCompletingTask();
}
@Override
diff --git
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
new file mode 100644
index 0000000000..0485e6aafc
--- /dev/null
+++
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.airavata.helix.impl.task.aws;
+
+import org.apache.airavata.helix.impl.task.AiravataTask;
+import org.apache.airavata.helix.impl.task.TaskContext;
+import org.apache.airavata.helix.impl.task.aws.utils.AWSTaskUtil;
+import org.apache.airavata.helix.task.api.TaskHelper;
+import org.apache.airavata.helix.task.api.annotation.TaskDef;
+import org.apache.airavata.model.status.ProcessState;
+import org.apache.helix.task.TaskResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@TaskDef(name = "AWS_COMPLETING_TASK")
+public class AWSCompletingTask extends AiravataTask {
+
+ private static final Logger logger =
LoggerFactory.getLogger(AWSCompletingTask.class);
+
+ @Override
+ public TaskResult onRun(TaskHelper helper, TaskContext taskContext) {
+ logger.info("Starting completing task for task {}, experiment id {}",
getTaskId(), getExperimentId());
+ logger.info("Process {} successfully completed", getProcessId());
+ saveAndPublishProcessStatus(ProcessState.COMPLETED);
+ cleanup();
+ AWSTaskUtil.terminateEC2Instance(getTaskContext(), getGatewayId());
+ return onSuccess("Process " + getProcessId() + " successfully
completed");
+ }
+
+ @Override
+ public void onCancel(TaskContext taskContext) {
+ }
+}
diff --git
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
index 27b9ccc80c..3ce5190fcb 100644
---
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
+++
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapBuilder.java
@@ -80,6 +80,7 @@ public class GroovyMapBuilder {
mapData.setWorkingDirectory(taskContext.getWorkingDir());
mapData.setTaskId(taskContext.getTaskId());
mapData.setExperimentDataDir(taskContext.getProcessModel().getExperimentDataDir());
+ mapData.setExperimentId(taskContext.getExperimentId());
SimpleDateFormat gmtDateFormat = new
SimpleDateFormat("yyyy-MM-dd+HH:mmZ");
gmtDateFormat.setTimeZone(TimeZone.getTimeZone("EST"));
@@ -121,6 +122,7 @@ public class GroovyMapBuilder {
((JobSubmissionTaskModel)
taskContext.getSubTaskModel());
if (jobSubmissionTaskModel.getWallTime() > 0) {
mapData.setMaxWallTime(maxWallTimeCalculator(jobSubmissionTaskModel.getWallTime()));
+
mapData.setWallTimeInSeconds(jobSubmissionTaskModel.getWallTime() * 60);
// TODO fix this
/*if (resourceJobManager != null) {
if
(resourceJobManager.getResourceJobManagerType().equals(ResourceJobManagerType.LSF))
{
@@ -161,6 +163,7 @@ public class GroovyMapBuilder {
// if so we ignore scheduling configuration.
if (scheduling.getWallTimeLimit() > 0 && mapData.getMaxWallTime()
== null) {
mapData.setMaxWallTime(maxWallTimeCalculator(scheduling.getWallTimeLimit()));
+ mapData.setWallTimeInSeconds(scheduling.getWallTimeLimit() *
60);
// TODO fix this
/*
diff --git
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
index 7eda6b97b1..2ba9423beb 100644
---
a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
+++
b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/GroovyMapData.java
@@ -107,6 +107,9 @@ public class GroovyMapData {
@ScriptTag(name = "maxWallTime")
private String maxWallTime;
+ @ScriptTag(name = "wallTimeInSeconds")
+ private Integer wallTimeInSeconds;
+
@ScriptTag(name = "qualityOfService")
private String qualityOfService;
@@ -152,6 +155,9 @@ public class GroovyMapData {
@ScriptTag(name = "experimentDataDir")
private String experimentDataDir;
+ @ScriptTag(name = "experimentId")
+ private String experimentId;
+
@ScriptTag(name = "computeHostName")
private String computeHostName;
@@ -363,6 +369,14 @@ public class GroovyMapData {
return this;
}
+ public Integer getWallTimeInSeconds() {
+ return wallTimeInSeconds;
+ }
+
+ public void setWallTimeInSeconds(Integer wallTimeInSeconds) {
+ this.wallTimeInSeconds = wallTimeInSeconds;
+ }
+
public String getQualityOfService() {
return qualityOfService;
}
@@ -496,6 +510,14 @@ public class GroovyMapData {
this.experimentDataDir = experimentDataDir;
}
+ public String getExperimentId() {
+ return experimentId;
+ }
+
+ public void setExperimentId(String experimentId) {
+ this.experimentId = experimentId;
+ }
+
public String getCurrentTime() {
return currentTime;
}
diff --git a/airavata-api/src/main/resources/templates/CLOUD_Groovy.template
b/airavata-api/src/main/resources/templates/CLOUD_Groovy.template
index ab644476aa..c06dba149d 100644
--- a/airavata-api/src/main/resources/templates/CLOUD_Groovy.template
+++ b/airavata-api/src/main/resources/templates/CLOUD_Groovy.template
@@ -1,6 +1,9 @@
#!${shellName}
# Cloud execution script generated by Apache Airavata
+# User: ${gatewayUserName}
+# Experiment ID: ${experimentId}
+# Walltime (seconds): ${wallTimeInSeconds}
<%
if (exports != null) for(com in exports) out.print 'export ' + com +'\n'
if (moduleCommands != null) for(mc in moduleCommands) out.print mc +'\n'
@@ -9,6 +12,22 @@
if (jobSubmitterCommand != null && jobSubmitterCommand != "") out.print
jobSubmitterCommand + ' '
if (executablePath != null && executablePath != "") out.print
executablePath + ' '
if (inputs != null) for(input in inputs) out.print input + ' '
- out.print '\n'
- if (postJobCommands != null) for(pjc in postJobCommands) out.print pjc
+'\n'
-%>
\ No newline at end of file
+ out.print '&\n'
+ out.print 'MAIN_JOB_PID=\\$!\n'
+%>
+
+(
+ sleep ${wallTimeInSeconds}
+
+ if ps -p \$MAIN_JOB_PID > /dev/null; then
+ echo "Walltime of ${wallTimeInSeconds} seconds exceeded. Terminating job
PID \$MAIN_JOB_PID." >&2
+ pkill -P \$MAIN_JOB_PID
+ kill -9 \$MAIN_JOB_PID
+ fi
+) &
+
+WATCHDOG_PID=\$!
+wait \$MAIN_JOB_PID
+kill \$WATCHDOG_PID 2>/dev/null
+
+<% if (postJobCommands != null) for(pjc in postJobCommands) out.print pjc
+'\n' %>
\ No newline at end of file