Skip to content
This repository was archived by the owner on Aug 29, 2026. It is now read-only.

Commit c7befcc

Browse files
committed
fix: improve activity verification and output handling in HPC runtime service
1 parent 8e389c9 commit c7befcc

3 files changed

Lines changed: 75 additions & 70 deletions

File tree

‎pkg/server/runtimes/hpc_runtime/hpc_runtime_service/hpc_runtime_service.go‎

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package hpc_runtime_service
33
import (
44
"fmt"
55
"regexp"
6+
"strconv"
67
"strings"
78

89
"github.com/ovvesley/akoflow/pkg/server/config"
@@ -200,88 +201,102 @@ func (s *HPCRuntimeService) extractJobID(outputCommand string) (string, error) {
200201
func (s *HPCRuntimeService) VerifyActivitiesWasFinished(workflow workflow_entity.Workflow) bool {
201202
config.App().Logger.Infof("WORKER: Verify activities was finished in HPCRuntime")
202203

204+
finishedActivities := s.getFinishedActivities(workflow)
205+
if len(finishedActivities) == 0 {
206+
return true
207+
}
208+
209+
syncNeeded := false
203210
for _, activity := range workflow.Spec.Activities {
204-
if activity.GetRuntimeId() == s.runtimeName {
205-
s.handleVerifyActivityWasFinished(activity, workflow)
211+
if activity.GetRuntimeId() != s.runtimeName {
212+
continue
213+
}
214+
215+
if _, ok := finishedActivities[activity.Id]; !ok {
216+
continue
217+
}
218+
219+
if s.handleVerifyActivityWasFinished(activity) {
220+
syncNeeded = true
206221
}
207222
}
223+
224+
if syncNeeded {
225+
s.syncWorkflowVolumes(workflow)
226+
}
227+
208228
return true
209229
}
210230

211-
func (s *HPCRuntimeService) handleVerifyActivityWasFinished(activity workflow_activity_entity.WorkflowActivities, wf workflow_entity.Workflow) int {
212-
println("Verifying activity: ", activity.Name, " with id: ", activity.Id)
213-
214-
wfaDatabase, _ := s.activityRepository.Find(activity.Id)
231+
func (s *HPCRuntimeService) getFinishedActivities(workflow workflow_entity.Workflow) map[int]struct{} {
232+
finishedActivities := make(map[int]struct{})
215233

216-
if wfaDatabase.Status == activity_repository.StatusFinished {
217-
return activity_repository.StatusFinished
234+
runtimeName := s.runtimeName
235+
if runtimeName == "" && len(workflow.GetRuntimeId()) > 0 {
236+
runtimeName = workflow.GetRuntimeId()[0]
218237
}
219238

220-
if wfaDatabase.Status == activity_repository.StatusCreated {
221-
return activity_repository.StatusCreated
239+
if runtimeName == "" {
240+
return finishedActivities
222241
}
223242

224-
runtime, err := s.runtimeRepository.GetByName(activity.GetRuntimeId())
225-
243+
runtime, err := s.runtimeRepository.GetByName(runtimeName)
226244
if err != nil {
227245
config.App().Logger.Infof("WORKER: Error getting runtime from database.")
228-
return activity_repository.StatusRunning
246+
return finishedActivities
229247
}
230248

231-
if wfaDatabase.GetProcId() == "" {
232-
config.App().Logger.Infof("WORKER: Activity %d has no process ID", activity.Id)
233-
return activity_repository.StatusRunning
249+
sharedMountPath := workflow.GetMountPath()
250+
if sharedMountPath == "" {
251+
sharedMountPath = runtime.GetCurrentRuntimeMetadata("MOUNT_PATH")
234252
}
235253

236-
commandVerify := fmt.Sprintf("cat %s/akoflow_finished_%d_%d.txt", runtime.GetCurrentRuntimeMetadata("MOUNT_PATH"), wf.GetId(), activity.Id)
254+
commandVerify := fmt.Sprintf("find %s -maxdepth 1 -type f -name 'akoflow_finished_%d_*.txt' -print", sharedMountPath, workflow.GetId())
255+
output, err := s.connectorHPCRuntime.SetRuntime(*runtime).RunCommandWithOutputRemote(commandVerify)
256+
if err != nil {
257+
config.App().Logger.Infof("WORKER: Error listing finished activities for workflow %d", workflow.GetId())
258+
return finishedActivities
259+
}
237260

238-
output, _ := s.connectorHPCRuntime.SetRuntime(*runtime).RunCommandWithOutputRemote(commandVerify)
261+
re := regexp.MustCompile(fmt.Sprintf(`akoflow_finished_%d_(\d+)\.txt`, workflow.GetId()))
262+
for _, match := range re.FindAllStringSubmatch(output, -1) {
263+
if len(match) < 2 {
264+
continue
265+
}
239266

240-
scontrolResponse, err := s.extractJobIsFinished(output)
267+
activityID, err := strconv.Atoi(strings.TrimSpace(match[1]))
268+
if err != nil {
269+
continue
270+
}
241271

242-
if err != nil {
243-
config.App().Logger.Infof("WORKER: Error extracting job ID %s", strings.TrimSpace(wfaDatabase.GetProcId()))
244-
return activity_repository.StatusRunning
272+
finishedActivities[activityID] = struct{}{}
245273
}
246274

247-
if scontrolResponse.State == "COMPLETED" {
248-
config.App().Logger.Infof("WORKER: Activity %d finished", activity.Id)
249-
s.syncWorkflowVolumes(wf)
250-
_ = s.activityRepository.UpdateStatus(activity.Id, activity_repository.StatusFinished)
251-
return activity_repository.StatusFinished
252-
}
275+
return finishedActivities
276+
}
253277

254-
if scontrolResponse.State == "FAILED" || scontrolResponse.State == "CANCELLED+" || scontrolResponse.State == "CANCELLED" || scontrolResponse.State == "DEADLINE" || scontrolResponse.State == "TIMEOUT" || scontrolResponse.State == "OUT_OF_MEM+" {
255-
config.App().Logger.Infof("WORKER: Activity %d failed", activity.Id)
256-
s.syncWorkflowVolumes(wf)
257-
_ = s.activityRepository.UpdateStatus(activity.Id, activity_repository.StatusFinished)
258-
return activity_repository.StatusFinished
259-
}
278+
func (s *HPCRuntimeService) handleVerifyActivityWasFinished(activity workflow_activity_entity.WorkflowActivities) bool {
279+
println("Verifying activity: ", activity.Name, " with id: ", activity.Id)
260280

261-
if scontrolResponse.State == "RUNNING" {
262-
config.App().Logger.Infof("WORKER: Activity %d running", activity.Id)
263-
_ = s.activityRepository.UpdateStatus(activity.Id, activity_repository.StatusRunning)
264-
return activity_repository.StatusRunning
281+
wfaDatabase, _ := s.activityRepository.Find(activity.Id)
282+
283+
if wfaDatabase.Status == activity_repository.StatusFinished {
284+
return false
265285
}
266286

267-
if scontrolResponse.State == "PENDING" {
268-
config.App().Logger.Infof("WORKER: Activity %d pending", activity.Id)
269-
_ = s.activityRepository.UpdateStatus(activity.Id, activity_repository.StatusRunning)
270-
return activity_repository.StatusRunning
287+
if wfaDatabase.Status == activity_repository.StatusCreated {
288+
return false
271289
}
272290

273-
return activity_repository.StatusRunning
291+
if wfaDatabase.GetProcId() == "" {
292+
config.App().Logger.Infof("WORKER: Activity %d has no process ID", activity.Id)
293+
return false
294+
}
274295

275-
}
296+
config.App().Logger.Infof("WORKER: Activity %d finished", activity.Id)
297+
_ = s.activityRepository.UpdateStatus(activity.Id, activity_repository.StatusFinished)
298+
return true
276299

277-
type SaactResponse struct {
278-
JobID string `json:"JobID"`
279-
JobName string `json:"JobName"`
280-
Partition string `json:"Partition"`
281-
Account string `json:"Account"`
282-
AllocCPUs string `json:"AllocCPUs"`
283-
State string `json:"State"`
284-
ExitCode string `json:"ExitCode"`
285300
}
286301

287302
func extractField(pattern, text string) (string, error) {
@@ -293,18 +308,6 @@ func extractField(pattern, text string) (string, error) {
293308
return match[1], nil
294309
}
295310

296-
func (s *HPCRuntimeService) extractJobIsFinished(output string) (SaactResponse, error) {
297-
// verify if output contains "AKOFLOW_JOB_FINISHED"
298-
if !strings.Contains(output, "AKOFLOW_JOB_FINISHED") {
299-
return SaactResponse{}, fmt.Errorf("job not finished")
300-
}
301-
302-
return SaactResponse{
303-
State: "COMPLETED",
304-
}, nil
305-
306-
}
307-
308311
func (s *HPCRuntimeService) HealthCheck(runtimeName string) bool {
309312
config.App().Logger.Infof("WORKER: Health check HPCRuntime")
310313

‎pkg/server/runtimes/hpc_runtime/hpc_runtime_service/make_sbatch_hpc_activity_service.go‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,15 @@ func (m MakeSBatchHPCRuntimeActivityService) GetTemplateSbatch() string {
6060
func (m MakeSBatchHPCRuntimeActivityService) Handle(workflow workflow_entity.Workflow, activity workflow_activity_entity.WorkflowActivities) string {
6161

6262
templateSbatch := m.GetTemplateSbatch()
63+
sharedMountPath := workflow.GetMountPath()
64+
if sharedMountPath == "" {
65+
sharedMountPath = m.runtime.GetCurrentRuntimeMetadata("MOUNT_PATH")
66+
}
6367

6468
jobName := fmt.Sprintf("akoflow_%d_%d", workflow.GetId(), activity.GetId())
6569

66-
output := fmt.Sprintf("%s/akoflow_out_%d_%d.out", m.runtime.GetCurrentRuntimeMetadata("MOUNT_PATH"), workflow.GetId(), activity.GetId())
67-
error := fmt.Sprintf("%s/akoflow_err_%d_%d.err", m.runtime.GetCurrentRuntimeMetadata("MOUNT_PATH"), workflow.GetId(), activity.GetId())
70+
output := fmt.Sprintf("%s/akoflow_out_%d_%d.out", sharedMountPath, workflow.GetId(), activity.GetId())
71+
error := fmt.Sprintf("%s/akoflow_err_%d_%d.err", sharedMountPath, workflow.GetId(), activity.GetId())
6872
time := m.runtime.GetCurrentRuntimeMetadata("TIME")
6973
partition := m.runtime.GetCurrentRuntimeMetadata("QUEUE")
7074
ntasks := m.runtime.GetCurrentRuntimeMetadata("NTASKS")
@@ -86,7 +90,7 @@ func (m MakeSBatchHPCRuntimeActivityService) Handle(workflow workflow_entity.Wor
8690
templateSbatch = strings.ReplaceAll(templateSbatch, "#MEM#", mem)
8791
templateSbatch = strings.ReplaceAll(templateSbatch, "#COMMAND#", wrap)
8892

89-
templateSbatch += "\n\necho AKOFLOW_JOB_FINISHED > " + fmt.Sprintf("%s/akoflow_finished_%d_%d.txt", m.runtime.GetCurrentRuntimeMetadata("MOUNT_PATH"), workflow.GetId(), activity.GetId())
93+
templateSbatch += "\n\necho AKOFLOW_JOB_FINISHED > " + fmt.Sprintf("%s/akoflow_finished_%d_%d.txt", sharedMountPath, workflow.GetId(), activity.GetId())
9094

9195
templateSbatchBase64 := base64.StdEncoding.EncodeToString([]byte(templateSbatch))
9296

‎pkg/server/runtimes/singularity_runtime/singularity_runtime_service/make_singularity_activity_service.go‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,8 @@ func (s *MakeSingularityActivityService) MakeContainerCommandActivityToHPC(wf wo
6565
commandBase64 := base64.StdEncoding.EncodeToString([]byte(command))
6666
commandFinal := "echo " + commandBase64 + " | base64 -d | sh"
6767

68-
entryPoint := fmt.Sprintf("singularity exec --bind %s:%s --pwd %s %s bash -c '%s'",
68+
entryPoint := fmt.Sprintf("singularity exec --bind %s:/akoflow-wfa-shared --pwd /akoflow-wfa-shared %s bash -c '%s'",
6969
mountPath,
70-
mountPath,
71-
"/akoflow-wfa-shared ",
7270
imageSifPath,
7371
commandFinal,
7472
)

0 commit comments

Comments
 (0)