Skip to content

Commit 95e0f4e

Browse files
feat: update ReplicateStatusCause serialization and worker_api to support new WorkflowError format
1 parent 469aea6 commit 95e0f4e

File tree

8 files changed

+279
-149
lines changed

8 files changed

+279
-149
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pre-compute/src/api/worker_api.rs

Lines changed: 64 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,6 @@ use crate::compute::{
44
};
55
use log::error;
66
use reqwest::{blocking::Client, header::AUTHORIZATION};
7-
use serde::Serialize;
8-
9-
/// Represents payload that can be sent to the worker API to report the outcome of the
10-
/// pre‑compute stage.
11-
///
12-
/// The JSON structure expected by the REST endpoint is:
13-
/// ```json
14-
/// {
15-
/// "cause": "<ReplicateStatusCause as string>"
16-
/// }
17-
/// ```
18-
///
19-
/// # Arguments
20-
///
21-
/// * `cause` - A reference to the ReplicateStatusCause indicating why the pre-compute operation exited
22-
///
23-
/// # Example
24-
///
25-
/// ```rust
26-
/// use tee_worker_pre_compute::api::worker_api::ExitMessage;
27-
/// use tee_worker_pre_compute::compute::errors::ReplicateStatusCause;
28-
///
29-
/// let exit_message = ExitMessage::from(&ReplicateStatusCause::PreComputeInvalidTeeSignature);
30-
/// ```
31-
#[derive(Serialize, Debug)]
32-
pub struct ExitMessage<'a> {
33-
pub cause: &'a ReplicateStatusCause,
34-
}
35-
36-
impl<'a> From<&'a ReplicateStatusCause> for ExitMessage<'a> {
37-
fn from(cause: &'a ReplicateStatusCause) -> Self {
38-
Self { cause }
39-
}
40-
}
417

428
/// Thin wrapper around a [`Client`] that knows how to reach the iExec worker API.
439
///
@@ -93,21 +59,21 @@ impl WorkerApiClient {
9359
Self::new(&base_url)
9460
}
9561

96-
/// Sends an exit cause for a pre-compute operation to the Worker API.
62+
/// Sends exit causes for a pre-compute operation to the Worker API.
9763
///
98-
/// This method reports the exit cause of a pre-compute operation to the Worker API,
64+
/// This method reports the exit causes of a pre-compute operation to the Worker API,
9965
/// which can be used for tracking and debugging purposes.
10066
///
10167
/// # Arguments
10268
///
10369
/// * `authorization` - The authorization token to use for the API request
104-
/// * `chain_task_id` - The chain task ID for which to report the exit cause
105-
/// * `exit_cause` - The exit cause to report
70+
/// * `chain_task_id` - The chain task ID for which to report the exit causes
71+
/// * `exit_causes` - The list of exit causes to report
10672
///
10773
/// # Returns
10874
///
109-
/// * `Ok(())` - If the exit cause was successfully reported
110-
/// * `Err(Error)` - If the exit cause could not be reported due to an HTTP error
75+
/// * `Ok(())` - If the exit causes were successfully reported
76+
/// * `Err(Error)` - If the exit causes could not be reported due to an HTTP error
11177
///
11278
/// # Errors
11379
///
@@ -117,33 +83,33 @@ impl WorkerApiClient {
11783
/// # Example
11884
///
11985
/// ```rust
120-
/// use tee_worker_pre_compute::api::worker_api::{ExitMessage, WorkerApiClient};
86+
/// use tee_worker_pre_compute::api::worker_api::WorkerApiClient;
12187
/// use tee_worker_pre_compute::compute::errors::ReplicateStatusCause;
12288
///
12389
/// let client = WorkerApiClient::new("http://worker:13100");
124-
/// let exit_message = ExitMessage::from(&ReplicateStatusCause::PreComputeInvalidTeeSignature);
90+
/// let exit_causes = vec![ReplicateStatusCause::PreComputeInvalidTeeSignature];
12591
///
126-
/// match client.send_exit_cause_for_pre_compute_stage(
92+
/// match client.send_exit_causes_for_pre_compute_stage(
12793
/// "authorization_token",
12894
/// "0x123456789abcdef",
129-
/// &exit_message,
95+
/// &exit_causes,
13096
/// ) {
131-
/// Ok(()) => println!("Exit cause reported successfully"),
132-
/// Err(error) => eprintln!("Failed to report exit cause: {error}"),
97+
/// Ok(()) => println!("Exit causes reported successfully"),
98+
/// Err(error) => eprintln!("Failed to report exit causes: {error}"),
13399
/// }
134100
/// ```
135-
pub fn send_exit_cause_for_pre_compute_stage(
101+
pub fn send_exit_causes_for_pre_compute_stage(
136102
&self,
137103
authorization: &str,
138104
chain_task_id: &str,
139-
exit_cause: &ExitMessage,
105+
exit_causes: &Vec<ReplicateStatusCause>,
140106
) -> Result<(), ReplicateStatusCause> {
141107
let url = format!("{}/compute/pre/{chain_task_id}/exit", self.base_url);
142108
match self
143109
.client
144110
.post(&url)
145111
.header(AUTHORIZATION, authorization)
146-
.json(exit_cause)
112+
.json(exit_causes)
147113
.send()
148114
{
149115
Ok(resp) => {
@@ -152,12 +118,12 @@ impl WorkerApiClient {
152118
Ok(())
153119
} else {
154120
let body = resp.text().unwrap_or_default();
155-
error!("Failed to send exit cause: [status:{status}, body:{body}]");
121+
error!("Failed to send exit causes: [status:{status}, body:{body}]");
156122
Err(ReplicateStatusCause::PreComputeFailedUnknownIssue)
157123
}
158124
}
159125
Err(err) => {
160-
error!("HTTP request failed when sending exit cause to {url}: {err:?}");
126+
error!("HTTP request failed when sending exit causes to {url}: {err:?}");
161127
Err(ReplicateStatusCause::PreComputeFailedUnknownIssue)
162128
}
163129
}
@@ -175,31 +141,45 @@ mod tests {
175141
matchers::{body_json, header, method, path},
176142
};
177143

178-
// region ExitMessage()
144+
// region Serialization tests
179145
#[test]
180-
fn should_serialize_exit_message() {
181-
let causes = [
146+
fn should_serialize_replicate_status_cause() {
147+
let causes = vec![
182148
(
183149
ReplicateStatusCause::PreComputeInvalidTeeSignature,
184-
"PRE_COMPUTE_INVALID_TEE_SIGNATURE",
150+
r#"{"cause":"PRE_COMPUTE_INVALID_TEE_SIGNATURE","message":"Invalid TEE signature"}"#,
185151
),
186152
(
187153
ReplicateStatusCause::PreComputeWorkerAddressMissing,
188-
"PRE_COMPUTE_WORKER_ADDRESS_MISSING",
154+
r#"{"cause":"PRE_COMPUTE_WORKER_ADDRESS_MISSING","message":"Worker address related environment variable is missing"}"#,
189155
),
190156
(
191-
ReplicateStatusCause::PreComputeFailedUnknownIssue,
192-
"PRE_COMPUTE_FAILED_UNKNOWN_ISSUE",
157+
ReplicateStatusCause::PreComputeDatasetUrlMissing(2),
158+
r#"{"cause":"PRE_COMPUTE_DATASET_URL_MISSING","message":"Dataset URL related environment variable is missing for dataset 2"}"#,
159+
),
160+
(
161+
ReplicateStatusCause::PreComputeInvalidDatasetChecksum(1),
162+
r#"{"cause":"PRE_COMPUTE_INVALID_DATASET_CHECKSUM","message":"Invalid dataset checksum for dataset 1"}"#,
193163
),
194164
];
195165

196-
for (cause, message) in causes {
197-
let exit_message = ExitMessage::from(&cause);
198-
let serialized = to_string(&exit_message).expect("Failed to serialize");
199-
let expected = format!("{{\"cause\":\"{message}\"}}");
200-
assert_eq!(serialized, expected);
166+
for (cause, expected_json) in causes {
167+
let serialized = to_string(&cause).expect("Failed to serialize");
168+
assert_eq!(serialized, expected_json);
201169
}
202170
}
171+
172+
#[test]
173+
fn should_serialize_vec_of_causes() {
174+
let causes = vec![
175+
ReplicateStatusCause::PreComputeDatasetUrlMissing(0),
176+
ReplicateStatusCause::PreComputeInvalidDatasetChecksum(1),
177+
];
178+
179+
let serialized = to_string(&causes).expect("Failed to serialize");
180+
let expected = r#"[{"cause":"PRE_COMPUTE_DATASET_URL_MISSING","message":"Dataset URL related environment variable is missing for dataset 0"},{"cause":"PRE_COMPUTE_INVALID_DATASET_CHECKSUM","message":"Invalid dataset checksum for dataset 1"}]"#;
181+
assert_eq!(serialized, expected);
182+
}
203183
// endregion
204184

205185
// region get_worker_api_client
@@ -223,18 +203,21 @@ mod tests {
223203
}
224204
// endregion
225205

226-
// region send_exit_cause_for_pre_compute_stage()
206+
// region send_exit_causes_for_pre_compute_stage()
227207
const CHALLENGE: &str = "challenge";
228208
const CHAIN_TASK_ID: &str = "0x123456789abcdef";
229209

230210
#[tokio::test]
231-
async fn should_send_exit_cause() {
211+
async fn should_send_exit_causes() {
232212
let mock_server = MockServer::start().await;
233213
let server_url = mock_server.uri();
234214

235-
let expected_body = json!({
236-
"cause": ReplicateStatusCause::PreComputeInvalidTeeSignature,
237-
});
215+
let expected_body = json!([
216+
{
217+
"cause": "PRE_COMPUTE_INVALID_TEE_SIGNATURE",
218+
"message": "Invalid TEE signature"
219+
}
220+
]);
238221

239222
Mock::given(method("POST"))
240223
.and(path(format!("/compute/pre/{CHAIN_TASK_ID}/exit")))
@@ -246,13 +229,12 @@ mod tests {
246229
.await;
247230

248231
let result = tokio::task::spawn_blocking(move || {
249-
let exit_message =
250-
ExitMessage::from(&ReplicateStatusCause::PreComputeInvalidTeeSignature);
232+
let exit_causes = vec![ReplicateStatusCause::PreComputeInvalidTeeSignature];
251233
let worker_api_client = WorkerApiClient::new(&server_url);
252-
worker_api_client.send_exit_cause_for_pre_compute_stage(
234+
worker_api_client.send_exit_causes_for_pre_compute_stage(
253235
CHALLENGE,
254236
CHAIN_TASK_ID,
255-
&exit_message,
237+
&exit_causes,
256238
)
257239
})
258240
.await
@@ -262,7 +244,7 @@ mod tests {
262244
}
263245

264246
#[tokio::test]
265-
async fn should_not_send_exit_cause() {
247+
async fn should_not_send_exit_causes() {
266248
testing_logger::setup();
267249
let mock_server = MockServer::start().await;
268250
let server_url = mock_server.uri();
@@ -275,13 +257,12 @@ mod tests {
275257
.await;
276258

277259
let result = tokio::task::spawn_blocking(move || {
278-
let exit_message =
279-
ExitMessage::from(&ReplicateStatusCause::PreComputeFailedUnknownIssue);
260+
let exit_causes = vec![ReplicateStatusCause::PreComputeFailedUnknownIssue];
280261
let worker_api_client = WorkerApiClient::new(&server_url);
281-
let response = worker_api_client.send_exit_cause_for_pre_compute_stage(
262+
let response = worker_api_client.send_exit_causes_for_pre_compute_stage(
282263
CHALLENGE,
283264
CHAIN_TASK_ID,
284-
&exit_message,
265+
&exit_causes,
285266
);
286267
testing_logger::validate(|captured_logs| {
287268
let logs = captured_logs
@@ -292,7 +273,7 @@ mod tests {
292273
assert_eq!(logs.len(), 1);
293274
assert_eq!(
294275
logs[0].body,
295-
"Failed to send exit cause: [status:503 Service Unavailable, body:Service Unavailable]"
276+
"Failed to send exit causes: [status:503 Service Unavailable, body:Service Unavailable]"
296277
);
297278
});
298279
response
@@ -308,14 +289,14 @@ mod tests {
308289
}
309290

310291
#[test]
311-
fn test_send_exit_cause_http_request_failure() {
292+
fn test_send_exit_causes_http_request_failure() {
312293
testing_logger::setup();
313-
let exit_message = ExitMessage::from(&ReplicateStatusCause::PreComputeFailedUnknownIssue);
294+
let exit_causes = vec![ReplicateStatusCause::PreComputeFailedUnknownIssue];
314295
let worker_api_client = WorkerApiClient::new("wrong_url");
315-
let result = worker_api_client.send_exit_cause_for_pre_compute_stage(
296+
let result = worker_api_client.send_exit_causes_for_pre_compute_stage(
316297
CHALLENGE,
317298
CHAIN_TASK_ID,
318-
&exit_message,
299+
&exit_causes,
319300
);
320301
testing_logger::validate(|captured_logs| {
321302
let logs = captured_logs
@@ -326,7 +307,7 @@ mod tests {
326307
assert_eq!(logs.len(), 1);
327308
assert_eq!(
328309
logs[0].body,
329-
"HTTP request failed when sending exit cause to wrong_url/compute/pre/0x123456789abcdef/exit: reqwest::Error { kind: Builder, source: RelativeUrlWithoutBase }"
310+
"HTTP request failed when sending exit causes to wrong_url/compute/pre/0x123456789abcdef/exit: reqwest::Error { kind: Builder, source: RelativeUrlWithoutBase }"
330311
);
331312
});
332313
assert!(result.is_err());

pre-compute/src/compute/app_runner.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::api::worker_api::{ExitMessage, WorkerApiClient};
1+
use crate::api::worker_api::WorkerApiClient;
22
use crate::compute::pre_compute_app::{PreComputeApp, PreComputeAppTrait};
33
use crate::compute::{
44
errors::ReplicateStatusCause,
@@ -61,14 +61,12 @@ pub fn start_with_app<A: PreComputeAppTrait>(
6161
}
6262
};
6363

64-
let exit_message = ExitMessage {
65-
cause: &exit_cause.clone(),
66-
};
64+
let exit_causes = vec![exit_cause.clone()];
6765

68-
match WorkerApiClient::from_env().send_exit_cause_for_pre_compute_stage(
66+
match WorkerApiClient::from_env().send_exit_causes_for_pre_compute_stage(
6967
&authorization,
7068
chain_task_id,
71-
&exit_message,
69+
&exit_causes,
7270
) {
7371
Ok(_) => ExitMode::ReportedFailure,
7472
Err(_) => {
@@ -231,10 +229,10 @@ mod pre_compute_start_with_app_tests {
231229
async fn start_succeeds_when_send_exit_cause_api_success() {
232230
let mock_server = MockServer::start().await;
233231

234-
let expected_cause_enum = ReplicateStatusCause::PreComputeOutputFolderNotFound;
235-
let expected_exit_message_payload = json!({
236-
"cause": expected_cause_enum // Relies on ReplicateStatusCause's Serialize impl
237-
});
232+
let expected_exit_message_payload = json!([{
233+
"cause": "PRE_COMPUTE_OUTPUT_FOLDER_NOT_FOUND",
234+
"message": "Input files number related environment variable is missing"
235+
}]);
238236

239237
// Mock the worker API to return success
240238
Mock::given(method("POST"))

0 commit comments

Comments
 (0)