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.
2121import org .springframework .stereotype .Service ;
2222
2323import java .util .HashMap ;
24+ import java .util .List ;
2425
2526
2627@ Slf4j
2728@ Service
2829public class ComputeExitCauseService {
2930
30- private final HashMap <String , ReplicateStatusCause > exitCauseMap = new HashMap <>();
31+ private final HashMap <String , List < ReplicateStatusCause > > exitCauseMap = new HashMap <>();
3132
3233 /**
33- * Report failure exit cause from pre-compute or post-compute enclave.
34+ * Report failure exit causes from pre-compute or post-compute enclave.
35+ * Guarantees that exit causes can only be reported once per compute stage and task.
3436 *
3537 * @param computeStage pre-compute or post-compute-stage label
3638 * @param chainTaskId task ID
37- * @param exitCause root cause of the failure
38- * @return true if exit cause is reported
39+ * @param causes list of root causes of the failure
40+ * @return true if exit causes are reported, false if already reported
3941 */
40- boolean setExitCause (ComputeStage computeStage ,
41- String chainTaskId ,
42- ReplicateStatusCause exitCause ) {
43- String key = buildKey (computeStage , chainTaskId );
42+ boolean setExitCausesForGivenComputeStage (final ComputeStage computeStage ,
43+ final String chainTaskId ,
44+ final List <ReplicateStatusCause > causes ) {
45+ final String key = buildKey (computeStage , chainTaskId );
46+
4447 if (exitCauseMap .containsKey (key )) {
45- log .info ("Cannot set exit cause since already set " +
46- "[computeStage:{}, chainTaskId:{}, exitCause:{}]" ,
47- computeStage , chainTaskId , exitCause );
48+ log .warn ("Exit causes already reported for compute stage [computeStage:{}, chainTaskId:{}]" ,
49+ computeStage , chainTaskId );
4850 return false ;
4951 }
50- exitCauseMap .put (key , exitCause );
51- log .info ("Added exit cause [computeStage:{}, chainTaskId:{}, exitCause:{}]" ,
52- computeStage , chainTaskId , exitCause );
53- return true ;
54- }
55-
56- /**
57- * Get exit cause for pre-compute or post-compute enclave.
58- *
59- * @param chainTaskId task ID
60- * @return exit cause
61- */
62- ReplicateStatusCause getReplicateStatusCause (ComputeStage computeStage ,
63- String chainTaskId ) {
64- return exitCauseMap .get (buildKey (computeStage , chainTaskId ));
65- }
6652
67- /**
68- * Get pre-compute exit cause.
69- *
70- * @param chainTaskId task ID
71- * @return exit cause
72- */
73- public ReplicateStatusCause getPreComputeExitCauseAndPrune (String chainTaskId ) {
74- ComputeStage stage = ComputeStage .PRE ;
75- ReplicateStatusCause cause = getReplicateStatusCause (stage , chainTaskId );
76- pruneExitCause (stage , chainTaskId );
77- return cause != null ? cause : ReplicateStatusCause .PRE_COMPUTE_FAILED_UNKNOWN_ISSUE ;
53+ exitCauseMap .put (key , List .copyOf (causes ));
54+ log .info ("Added exit causes [computeStage:{}, chainTaskId:{}, causeCount:{}]" ,
55+ computeStage , chainTaskId , causes .size ());
56+ return true ;
7857 }
7958
8059 /**
81- * Get post-compute exit cause.
60+ * Get exit causes for a specific compute stage and prune them.
61+ * Returns default unknown issue cause when no specific causes are set.
8262 *
83- * @param chainTaskId task ID
84- * @return exit cause
63+ * @param computeStage compute stage
64+ * @param chainTaskId task ID
65+ * @param fallbackCause default cause to return if no specific causes are found
66+ * @return list of exit causes, or default unknown issue if not found
8567 */
86- public ReplicateStatusCause getPostComputeExitCauseAndPrune (String chainTaskId ) {
87- ComputeStage stage = ComputeStage .POST ;
88- ReplicateStatusCause cause = getReplicateStatusCause (stage , chainTaskId );
89- pruneExitCause (stage , chainTaskId );
90- return cause != null ? cause : ReplicateStatusCause .POST_COMPUTE_FAILED_UNKNOWN_ISSUE ;
68+ public List <ReplicateStatusCause > getExitCausesAndPruneForGivenComputeStage (
69+ final ComputeStage computeStage ,
70+ final String chainTaskId ,
71+ final ReplicateStatusCause fallbackCause ) {
72+ final String key = buildKey (computeStage , chainTaskId );
73+ final List <ReplicateStatusCause > causes = exitCauseMap .remove (key );
74+ if (causes != null ) {
75+ log .info ("Retrieved and pruned exit causes [computeStage:{}, chainTaskId:{}, causeCount:{}]" ,
76+ computeStage , chainTaskId , causes .size ());
77+ return causes ;
78+ } else {
79+ log .info ("No exit causes found, returning fallback cause [computeStage:{}, chainTaskId:{}]" ,
80+ computeStage , chainTaskId );
81+ return List .of (fallbackCause );
82+ }
9183 }
9284
9385 /**
@@ -100,15 +92,4 @@ public ReplicateStatusCause getPostComputeExitCauseAndPrune(String chainTaskId)
10092 private String buildKey (ComputeStage prefix , String chainTaskId ) {
10193 return prefix + "_" + chainTaskId ;
10294 }
103-
104- /**
105- * Prune exit cause.
106- *
107- * @param computeStage compute stage
108- * @param chainTaskId task ID
109- */
110- private void pruneExitCause (ComputeStage computeStage , String chainTaskId ) {
111- exitCauseMap .remove (buildKey (computeStage , chainTaskId ));
112- }
113-
114- }
95+ }
0 commit comments