Skip to content

Commit 0a884fe

Browse files
authored
feat: propagate list of exit causes (#657)
1 parent debade3 commit 0a884fe

13 files changed

+114
-104
lines changed

src/main/java/com/iexec/worker/compute/ComputeManagerService.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.time.Duration;
4141
import java.time.temporal.ChronoUnit;
4242
import java.util.HashMap;
43+
import java.util.List;
4344
import java.util.Map;
4445

4546
@Slf4j
@@ -229,20 +230,27 @@ public PostComputeResponse runPostCompute(final TaskDescription taskDescription,
229230
postComputeResponse = postComputeService.runTeePostCompute(taskDescription, secureSession);
230231
} else {
231232
postComputeResponse = PostComputeResponse.builder()
232-
.exitCause(ReplicateStatusCause.POST_COMPUTE_FAILED_UNKNOWN_ISSUE)
233+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_FAILED_UNKNOWN_ISSUE))
233234
.build();
234235
}
235236
if (!postComputeResponse.isSuccessful()) {
236237
return postComputeResponse;
237238
}
238239
final ComputedFile computedFile = resultService.readComputedFile(chainTaskId);
239240
if (computedFile == null) {
240-
postComputeResponse.setExitCause(ReplicateStatusCause.POST_COMPUTE_COMPUTED_FILE_NOT_FOUND);
241-
return postComputeResponse;
241+
return PostComputeResponse.builder()
242+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_COMPUTED_FILE_NOT_FOUND))
243+
.stdout(postComputeResponse.getStdout())
244+
.stderr(postComputeResponse.getStderr())
245+
.build();
242246
}
243247
final String resultDigest = resultService.computeResultDigest(computedFile);
244248
if (resultDigest.isEmpty()) {
245-
postComputeResponse.setExitCause(ReplicateStatusCause.POST_COMPUTE_RESULT_DIGEST_COMPUTATION_FAILED);
249+
return PostComputeResponse.builder()
250+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_RESULT_DIGEST_COMPUTATION_FAILED))
251+
.stdout(postComputeResponse.getStdout())
252+
.stderr(postComputeResponse.getStderr())
253+
.build();
246254
}
247255
resultService.saveResultInfo(taskDescription, computedFile);
248256
return postComputeResponse;

src/main/java/com/iexec/worker/compute/ComputeResponse.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,13 +18,18 @@
1818

1919
import com.iexec.common.replicate.ReplicateStatusCause;
2020

21+
import java.util.List;
22+
2123
public interface ComputeResponse {
2224

23-
ReplicateStatusCause getExitCause();
25+
List<ReplicateStatusCause> getExitCauses();
26+
2427
String getStdout();
28+
2529
String getStderr();
30+
2631
default boolean isSuccessful() {
27-
return getExitCause() == null;
32+
return getExitCauses().isEmpty();
2833
}
2934

3035
}
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,17 +18,18 @@
1818

1919
import com.iexec.common.replicate.ReplicateStatusCause;
2020
import com.iexec.worker.compute.ComputeResponse;
21-
import lombok.*;
21+
import lombok.Builder;
22+
import lombok.Value;
2223

23-
@Data
24+
import java.util.List;
25+
26+
@Value
2427
@Builder
25-
@Getter
26-
@NoArgsConstructor
27-
@AllArgsConstructor
2828
public class AppComputeResponse implements ComputeResponse {
2929

30-
private ReplicateStatusCause exitCause;
31-
private String stdout;
32-
private String stderr;
33-
private int exitCode;
34-
}
30+
@Builder.Default
31+
List<ReplicateStatusCause> exitCauses = List.of();
32+
String stdout;
33+
String stderr;
34+
int exitCode;
35+
}

src/main/java/com/iexec/worker/compute/app/AppComputeService.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public AppComputeResponse runCompute(final TaskDescription taskDescription,
104104
}
105105
final DockerRunFinalStatus finalStatus = dockerResponse.getFinalStatus();
106106
return AppComputeResponse.builder()
107-
.exitCause(getExitCauseFromFinalStatus(finalStatus))
107+
.exitCauses(getExitCauseFromFinalStatus(finalStatus))
108108
.stdout(dockerResponse.getStdout())
109109
.stderr(dockerResponse.getStderr())
110110
.exitCode(dockerResponse.getContainerExitCode())
@@ -119,12 +119,11 @@ private String getTaskContainerName(String chainTaskId) {
119119
return workerConfigService.getWorkerName() + "-" + chainTaskId;
120120
}
121121

122-
private ReplicateStatusCause getExitCauseFromFinalStatus(DockerRunFinalStatus finalStatus) {
123-
if (finalStatus == DockerRunFinalStatus.TIMEOUT) {
124-
return ReplicateStatusCause.APP_COMPUTE_TIMEOUT;
125-
} else if (finalStatus == DockerRunFinalStatus.FAILED) {
126-
return ReplicateStatusCause.APP_COMPUTE_FAILED;
127-
}
128-
return null;
122+
private List<ReplicateStatusCause> getExitCauseFromFinalStatus(DockerRunFinalStatus finalStatus) {
123+
return switch (finalStatus) {
124+
case TIMEOUT -> List.of(ReplicateStatusCause.APP_COMPUTE_TIMEOUT);
125+
case FAILED -> List.of(ReplicateStatusCause.APP_COMPUTE_FAILED);
126+
default -> List.of();
127+
};
129128
}
130129
}

src/main/java/com/iexec/worker/compute/post/PostComputeResponse.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,16 +18,17 @@
1818

1919
import com.iexec.common.replicate.ReplicateStatusCause;
2020
import com.iexec.worker.compute.ComputeResponse;
21-
import lombok.*;
21+
import lombok.Builder;
22+
import lombok.Value;
2223

23-
@Data
24+
import java.util.List;
25+
26+
@Value
2427
@Builder
25-
@Getter
26-
@NoArgsConstructor
27-
@AllArgsConstructor
2828
public class PostComputeResponse implements ComputeResponse {
2929

30-
private ReplicateStatusCause exitCause;
31-
private String stdout;
32-
private String stderr;
30+
@Builder.Default
31+
List<ReplicateStatusCause> exitCauses = List.of();
32+
String stdout;
33+
String stderr;
3334
}

src/main/java/com/iexec/worker/compute/post/PostComputeService.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public PostComputeResponse runStandardPostCompute(TaskDescription taskDescriptio
111111
final Optional<ReplicateStatusCause> resultFilesNameError = checkResultFilesName(chainTaskId, taskIexecOutDir);
112112
if (resultFilesNameError.isPresent()) {
113113
return PostComputeResponse.builder()
114-
.exitCause(resultFilesNameError.get())
114+
.exitCauses(List.of(resultFilesNameError.get()))
115115
.build();
116116
}
117117

@@ -122,7 +122,7 @@ public PostComputeResponse runStandardPostCompute(TaskDescription taskDescriptio
122122
taskOutputDir);
123123
if (zipIexecOutPath.isEmpty()) {
124124
return PostComputeResponse.builder()
125-
.exitCause(ReplicateStatusCause.POST_COMPUTE_OUT_FOLDER_ZIP_FAILED)
125+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_OUT_FOLDER_ZIP_FAILED))
126126
.build();
127127
}
128128
// copy /output/iexec_out/computed.json to /output/computed.json as in FlowService#sendComputedFileToHost
@@ -133,7 +133,7 @@ public PostComputeResponse runStandardPostCompute(TaskDescription taskDescriptio
133133
if (!isCopied) {
134134
log.error("Failed to copy computed.json file to /output [chainTaskId:{}]", chainTaskId);
135135
return PostComputeResponse.builder()
136-
.exitCause(ReplicateStatusCause.POST_COMPUTE_SEND_COMPUTED_FILE_FAILED)
136+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_SEND_COMPUTED_FILE_FAILED))
137137
.build();
138138
}
139139
return PostComputeResponse.builder().build();
@@ -177,7 +177,7 @@ public PostComputeResponse runTeePostCompute(TaskDescription taskDescription,
177177
log.error("Tee post-compute image not found locally [chainTaskId:{}]",
178178
chainTaskId);
179179
return PostComputeResponse.builder()
180-
.exitCause(ReplicateStatusCause.POST_COMPUTE_IMAGE_MISSING)
180+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_IMAGE_MISSING))
181181
.build();
182182
}
183183
TeeService teeService = teeServicesManager.getTeeService(taskDescription.getTeeFramework());
@@ -215,7 +215,7 @@ public PostComputeResponse runTeePostCompute(TaskDescription taskDescription,
215215
" [chainTaskId:{}, maxExecutionTime:{}]",
216216
chainTaskId, taskDescription.getMaxExecutionTime());
217217
return PostComputeResponse.builder()
218-
.exitCause(ReplicateStatusCause.POST_COMPUTE_TIMEOUT)
218+
.exitCauses(List.of(ReplicateStatusCause.POST_COMPUTE_TIMEOUT))
219219
.build();
220220
}
221221
if (finalStatus == DockerRunFinalStatus.FAILED) {
@@ -224,7 +224,7 @@ public PostComputeResponse runTeePostCompute(TaskDescription taskDescription,
224224
log.error("Failed to run tee post-compute [chainTaskId:{}, " +
225225
"exitCode:{}, exitCause:{}]", chainTaskId, exitCode, exitCause);
226226
return PostComputeResponse.builder()
227-
.exitCause(exitCause)
227+
.exitCauses(List.of(exitCause))
228228
.build();
229229
}
230230
return PostComputeResponse.builder()
Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2020 IEXEC BLOCKCHAIN TECH
2+
* Copyright 2020-2025 IEXEC BLOCKCHAIN TECH
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,20 +19,21 @@
1919
import com.iexec.common.replicate.ReplicateStatusCause;
2020
import com.iexec.sms.api.TeeSessionGenerationResponse;
2121
import com.iexec.worker.compute.ComputeResponse;
22-
import lombok.*;
22+
import lombok.Builder;
23+
import lombok.Value;
2324

24-
@Data
25+
import java.util.List;
26+
27+
@Value
2528
@Builder
26-
@Getter
27-
@NoArgsConstructor
28-
@AllArgsConstructor
2929
public class PreComputeResponse implements ComputeResponse {
3030

31-
private ReplicateStatusCause exitCause;
32-
private boolean isTeeTask;
33-
private TeeSessionGenerationResponse secureSession;
34-
private String stdout;
35-
private String stderr;
31+
@Builder.Default
32+
List<ReplicateStatusCause> exitCauses = List.of();
33+
boolean isTeeTask;
34+
TeeSessionGenerationResponse secureSession;
35+
String stdout;
36+
String stderr;
3637

3738

3839
@Override
@@ -42,8 +43,4 @@ public boolean isSuccessful() {
4243
}
4344
return ComputeResponse.super.isSuccessful();
4445
}
45-
46-
public void setExitCause(ReplicateStatusCause exitCause) {
47-
this.exitCause = exitCause;
48-
}
49-
}
46+
}

src/main/java/com/iexec/worker/compute/pre/PreComputeService.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,14 @@ public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, Work
103103
if (enclaveConfig == null) {
104104
log.error("No enclave configuration found for task [chainTaskId:{}]", chainTaskId);
105105
return preComputeResponseBuilder
106-
.exitCause(PRE_COMPUTE_MISSING_ENCLAVE_CONFIGURATION)
106+
.exitCauses(List.of(PRE_COMPUTE_MISSING_ENCLAVE_CONFIGURATION))
107107
.build();
108108
}
109109
if (!enclaveConfig.getValidator().isValid()) {
110110
log.error("Invalid enclave configuration [chainTaskId:{}, violations:{}]",
111111
chainTaskId, enclaveConfig.getValidator().validate().toString());
112112
return preComputeResponseBuilder
113-
.exitCause(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION)
113+
.exitCauses(List.of(PRE_COMPUTE_INVALID_ENCLAVE_CONFIGURATION))
114114
.build();
115115
}
116116
long teeComputeMaxHeapSize = DataSize
@@ -120,7 +120,7 @@ public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, Work
120120
log.error("Enclave configuration should define a proper heap " +
121121
"size [chainTaskId:{}, heapSize:{}, maxHeapSize:{}]",
122122
chainTaskId, enclaveConfig.getHeapSize(), teeComputeMaxHeapSize);
123-
preComputeResponseBuilder.exitCause(PRE_COMPUTE_INVALID_ENCLAVE_HEAP_CONFIGURATION);
123+
preComputeResponseBuilder.exitCauses(List.of(PRE_COMPUTE_INVALID_ENCLAVE_HEAP_CONFIGURATION));
124124
return preComputeResponseBuilder.build();
125125
}
126126
// create secure session
@@ -134,37 +134,37 @@ public PreComputeResponse runTeePreCompute(TaskDescription taskDescription, Work
134134
} catch (TeeSessionGenerationException e) {
135135
log.error("Failed to create TEE secure session [chainTaskId:{}]", chainTaskId, e);
136136
return preComputeResponseBuilder
137-
.exitCause(teeSessionGenerationErrorToReplicateStatusCause(e.getTeeSessionGenerationError()))
137+
.exitCauses(List.of(teeSessionGenerationErrorToReplicateStatusCause(e.getTeeSessionGenerationError())))
138138
.build();
139139
}
140140

141141
// run TEE pre-compute container if needed
142142
if (taskDescription.requiresPreCompute()) {
143143
log.info("Task contains TEE input data [chainTaskId:{}, containsDataset:{}, containsInputFiles:{}]",
144144
chainTaskId, taskDescription.containsDataset(), taskDescription.containsInputFiles());
145-
final ReplicateStatusCause exitCause = downloadDatasetAndFiles(taskDescription, secureSession);
146-
preComputeResponseBuilder.exitCause(exitCause);
145+
final List<ReplicateStatusCause> exitCauses = downloadDatasetAndFiles(taskDescription, secureSession);
146+
preComputeResponseBuilder.exitCauses(exitCauses);
147147
}
148148

149149
return preComputeResponseBuilder.build();
150150
}
151151

152-
private ReplicateStatusCause downloadDatasetAndFiles(
152+
private List<ReplicateStatusCause> downloadDatasetAndFiles(
153153
TaskDescription taskDescription,
154154
TeeSessionGenerationResponse secureSession) {
155155
try {
156156
Integer exitCode = prepareTeeInputData(taskDescription, secureSession);
157157
if (exitCode == null || exitCode != 0) {
158158
String chainTaskId = taskDescription.getChainTaskId();
159-
ReplicateStatusCause exitCause = getExitCause(chainTaskId, exitCode);
160-
log.error("Failed to prepare TEE input data [chainTaskId:{}, exitCode:{}, exitCause:{}]",
159+
ReplicateStatusCause exitCause = getExitCause(chainTaskId, exitCode); // TODO: Handle list of exit causes
160+
log.error("Failed to prepare TEE input data [chainTaskId:{}, exitCode:{}, exitCauses:{}]",
161161
chainTaskId, exitCode, exitCause);
162-
return exitCause;
162+
return List.of(exitCause);
163163
}
164164
} catch (TimeoutException e) {
165-
return PRE_COMPUTE_TIMEOUT;
165+
return List.of(PRE_COMPUTE_TIMEOUT);
166166
}
167-
return null;
167+
return List.of();
168168
}
169169

170170
private ReplicateStatusCause getExitCause(String chainTaskId, Integer exitCode) {

src/main/java/com/iexec/worker/task/TaskManagerService.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ ReplicateActionResponse compute(TaskDescription taskDescription) {
250250
workerpoolAuthorization);
251251
if (!preResponse.isSuccessful()) {
252252
return getFailureResponseAndPrintError(
253-
preResponse.getExitCause(),
253+
preResponse.getExitCauses().get(0), //TODO: Handle list of causes
254254
context,
255255
chainTaskId
256256
);
@@ -260,7 +260,7 @@ ReplicateActionResponse compute(TaskDescription taskDescription) {
260260
computeManagerService.runCompute(taskDescription,
261261
preResponse.getSecureSession());
262262
if (!appResponse.isSuccessful()) {
263-
final ReplicateStatusCause cause = appResponse.getExitCause();
263+
final ReplicateStatusCause cause = appResponse.getExitCauses().get(0); //TODO: Handle list of causes
264264
logError(cause, context, chainTaskId);
265265
return ReplicateActionResponse.failureWithDetails(
266266
ReplicateStatusDetails.builder()
@@ -279,9 +279,9 @@ ReplicateActionResponse compute(TaskDescription taskDescription) {
279279
computeManagerService.runPostCompute(taskDescription,
280280
preResponse.getSecureSession());
281281
if (!postResponse.isSuccessful()) {
282-
ReplicateStatusCause cause = postResponse.getExitCause();
283-
logError(cause, context, chainTaskId);
284-
return ReplicateActionResponse.failureWithStdout(cause,
282+
ReplicateStatusCause causes = postResponse.getExitCauses().get(0); //TODO: Handle list of causes
283+
logError(causes, context, chainTaskId);
284+
return ReplicateActionResponse.failureWithStdout(causes,
285285
postResponse.getStdout());
286286
}
287287
return ReplicateActionResponse.successWithLogs(

0 commit comments

Comments
 (0)