batch_mode_process_response/
save_failed_entries.rs1crate::ix!();
3
4#[tracing::instrument(level="trace", skip_all)]
5pub async fn save_failed_entries(
6 workspace: &dyn BatchWorkspaceInterface,
7 failed_entries: &[&BatchResponseRecord],
8) -> Result<(), ErrorSavingFailedBatchEntries> {
9 trace!("Entering save_failed_entries.");
10
11 info!("saving failed entries: {:#?}", failed_entries);
12
13 let mut serialized_entries = String::new();
15 for entry in failed_entries {
16 let json_line = serde_json::to_string(entry)
17 .map_err(ErrorSavingFailedBatchEntries::from)?;
18 serialized_entries.push_str(&json_line);
19 serialized_entries.push('\n');
20 }
21
22 let file_path = workspace.failed_items_dir().join("failed_entries.jsonl");
24 debug!("Appending failed entries to file at path: {:?}", file_path);
25
26 if let Some(parent_dir) = file_path.parent() {
28 tokio::fs::create_dir_all(parent_dir)
29 .await
30 .map_err(ErrorSavingFailedBatchEntries::from)?;
31 }
32
33 use tokio::io::AsyncWriteExt;
35 let mut file = tokio::fs::OpenOptions::new()
36 .create(true)
37 .append(true)
38 .open(&file_path)
39 .await
40 .map_err(ErrorSavingFailedBatchEntries::from)?;
41
42 file.write_all(serialized_entries.as_bytes())
43 .await
44 .map_err(ErrorSavingFailedBatchEntries::from)?;
45
46 info!("save_failed_entries completed successfully.");
47 Ok(())
48}
49
50#[cfg(test)]
51mod save_failed_entries_tests {
52 use super::*;
53 use std::fs;
54
55 #[traced_test]
56 async fn test_save_failed_entries() {
57 trace!("===== BEGIN TEST: test_save_failed_entries =====");
59
60 let workspace = BatchWorkspace::new_temp().await.unwrap();
61 info!("Created workspace: {:?}", workspace);
62
63 let fail_details = BatchErrorDetailsBuilder::default()
64 .error_type(ErrorType::Unknown("some_error_type".to_string()))
65 .code(Some("xxx".to_string()))
66 .message("some error".to_string())
67 .build()
68 .unwrap();
69
70 let fail_errbody = BatchErrorResponseBodyBuilder::default()
71 .error(fail_details)
72 .build()
73 .unwrap();
74
75 let fail_respcontent = BatchResponseContentBuilder::default()
76 .status_code(400_u16)
77 .request_id(ResponseRequestId::new("resp_fail_1"))
78 .body(BatchResponseBody::Error(fail_errbody))
79 .build()
80 .unwrap();
81
82 let fail_rec = BatchResponseRecordBuilder::default()
83 .id(BatchRequestId::new("id"))
84 .custom_id(CustomRequestId::new("fail_1"))
85 .response(fail_respcontent)
86 .build()
87 .unwrap();
88
89 let failed_records = vec![ &fail_rec ];
90
91 let result = save_failed_entries(workspace.as_ref(), &failed_records).await;
93 assert!(result.is_ok(), "Saving failed entries should succeed");
94
95 let file_path = workspace.failed_items_dir().join("failed_entries.jsonl");
97 trace!("Asserting that failed-entries file path exists: {:?}", file_path);
98 assert!(
99 file_path.exists(),
100 "failed_entries.jsonl must be created in ephemeral failed_items_dir"
101 );
102
103 let contents = std::fs::read_to_string(&file_path)
105 .expect("Could not read appended failed_entries.jsonl");
106 assert!(contents.contains("\"fail_1\""));
107
108 trace!("===== END TEST: test_save_failed_entries =====");
109 }
110}