You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2020/04/10 07:12:41 UTC

[incubator-teaclave] branch develop updated: [task] Unify task result field with TaskResult (#262)

This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/develop by this push:
     new f2da494  [task] Unify task result field with TaskResult (#262)
f2da494 is described below

commit f2da494a806b597ac97ee56598c3ccb9e104bd4c
Author: Zhaofeng Chen <zf...@apache.org>
AuthorDate: Fri Apr 10 00:12:36 2020 -0700

    [task] Unify task result field with TaskResult (#262)
---
 services/execution/enclave/src/service.rs          |  7 +-
 services/management/enclave/src/service.rs         |  5 +-
 services/proto/proto_gen/templates/proto.j2        |  2 +-
 services/proto/src/proto/teaclave_common.proto     |  7 ++
 .../src/proto/teaclave_frontend_service.proto      |  5 +-
 .../src/proto/teaclave_scheduler_service.proto     |  5 +-
 services/proto/src/teaclave_common.rs              | 35 +++++++++-
 services/proto/src/teaclave_frontend_service.rs    | 12 ++--
 services/proto/src/teaclave_scheduler_service.rs   | 34 ++--------
 services/scheduler/enclave/src/service.rs          |  8 +--
 .../enclave/src/end_to_end/mesapy_echo.rs          | 24 ++-----
 tests/functional/enclave/src/end_to_end/mod.rs     | 41 ++++++++++++
 .../enclave/src/end_to_end/native_echo.rs          | 24 ++-----
 .../enclave/src/end_to_end/native_gbdt_training.rs | 66 +++++--------------
 tests/functional/enclave/src/execution_service.rs  |  2 +-
 types/src/task.rs                                  | 77 +++++++++++++++++++++-
 16 files changed, 205 insertions(+), 149 deletions(-)

diff --git a/services/execution/enclave/src/service.rs b/services/execution/enclave/src/service.rs
index d743cba..4f692d6 100644
--- a/services/execution/enclave/src/service.rs
+++ b/services/execution/enclave/src/service.rs
@@ -95,12 +95,17 @@ impl TeaclaveExecutionService {
     }
 
     fn invoke_task(&mut self, task: &StagedTask) -> Result<TaskOutputs> {
-        self.update_task_status(&task.task_id, TaskStatus::Running, String::new())?;
         let file_mgr = TaskFileManager::new(WORKER_BASE_DIR, task)?;
+
+        self.update_task_status(&task.task_id, TaskStatus::DataPreparing, String::new())?;
         let invocation = prepare_task(&task, &file_mgr)?;
+
         log::info!("Invoke function: {:?}", invocation);
+
+        self.update_task_status(&task.task_id, TaskStatus::Running, String::new())?;
         let worker = Worker::default();
         let summary = worker.invoke_function(invocation)?;
+
         finalize_task(&file_mgr)?;
         let task_outputs = TaskOutputs::new(summary.as_bytes(), hashmap!());
         Ok(task_outputs)
diff --git a/services/management/enclave/src/service.rs b/services/management/enclave/src/service.rs
index cd24c89..9b23e6f 100644
--- a/services/management/enclave/src/service.rs
+++ b/services/management/enclave/src/service.rs
@@ -319,6 +319,8 @@ impl TeaclaveManagement for TeaclaveManagementService {
             ServiceError::PermissionDenied
         );
 
+        log::info!("GetTask: {:?}", task);
+
         let response = GetTaskResponse {
             task_id: task.external_id(),
             creator: task.creator,
@@ -331,8 +333,7 @@ impl TeaclaveManagement for TeaclaveManagementService {
             approved_users: task.approved_users,
             input_map: task.input_map,
             output_map: task.output_map,
-            return_value: task.return_value.unwrap_or_default(),
-            output_file_hash: task.output_file_hash,
+            result: task.result,
             status: task.status,
         };
         Ok(response)
diff --git a/services/proto/proto_gen/templates/proto.j2 b/services/proto/proto_gen/templates/proto.j2
index 979c872..361573f 100644
--- a/services/proto/proto_gen/templates/proto.j2
+++ b/services/proto/proto_gen/templates/proto.j2
@@ -8,7 +8,7 @@ pub enum {{ service.proto_name }}Request {
 
 #[allow(clippy::large_enum_variant)]
 #[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
-#[serde(tag = "response", rename_all = "snake_case")]
+#[serde(tag = "response", content = "content", rename_all = "snake_case")]
 pub enum {{ service.proto_name }}Response {
     {%- for m in service.methods %}
     {{ m.proto_name }}({{ m.output_type }}),
diff --git a/services/proto/src/proto/teaclave_common.proto b/services/proto/src/proto/teaclave_common.proto
index feffe53..97ca19a 100644
--- a/services/proto/src/proto/teaclave_common.proto
+++ b/services/proto/src/proto/teaclave_common.proto
@@ -30,3 +30,10 @@ enum TaskStatus {
   Running = 5;
   Finished = 6;
 }
+
+message TaskResult {
+  oneof result {
+    teaclave_common_proto.TaskOutputs Ok = 1;
+    teaclave_common_proto.TaskFailure Err = 2;
+  }
+}
diff --git a/services/proto/src/proto/teaclave_frontend_service.proto b/services/proto/src/proto/teaclave_frontend_service.proto
index 6083827..29c1346 100644
--- a/services/proto/src/proto/teaclave_frontend_service.proto
+++ b/services/proto/src/proto/teaclave_frontend_service.proto
@@ -136,9 +136,8 @@ message GetTaskResponse {
   repeated string approved_users = 9;
   repeated DataMap input_map = 10;
   repeated DataMap output_map = 11;
-  bytes return_value = 12;
-  map<string, string> output_file_hash = 13;
-  teaclave_common_proto.TaskStatus status = 14;
+  teaclave_common_proto.TaskStatus status = 20;
+  teaclave_common_proto.TaskResult result = 21;
 }
 
 message AssignDataRequest {
diff --git a/services/proto/src/proto/teaclave_scheduler_service.proto b/services/proto/src/proto/teaclave_scheduler_service.proto
index ce96561..8a82565 100644
--- a/services/proto/src/proto/teaclave_scheduler_service.proto
+++ b/services/proto/src/proto/teaclave_scheduler_service.proto
@@ -22,10 +22,7 @@ message UpdateTaskStatusResponse {}
 
 message UpdateTaskResultRequest {
   string task_id = 1;
-  oneof TaskResult {
-    teaclave_common_proto.TaskOutputs Ok = 2;
-    teaclave_common_proto.TaskFailure Err = 3;
-  }
+  teaclave_common_proto.TaskResult result = 2;
 }
 message UpdateTaskResultResponse {}
 
diff --git a/services/proto/src/teaclave_common.rs b/services/proto/src/teaclave_common.rs
index 5b0c496..2c94caf 100644
--- a/services/proto/src/teaclave_common.rs
+++ b/services/proto/src/teaclave_common.rs
@@ -20,8 +20,9 @@ use std::prelude::v1::*;
 
 use crate::teaclave_common_proto as proto;
 use anyhow::{bail, Error, Result};
+use std::convert::TryInto;
 use teaclave_crypto::TeaclaveFile128Key;
-use teaclave_types::{FileCrypto, TaskFailure, TaskOutputs, TaskStatus};
+use teaclave_types::{FileCrypto, TaskFailure, TaskOutputs, TaskResult, TaskStatus};
 
 #[derive(Debug)]
 pub struct UserCredential {
@@ -163,3 +164,35 @@ impl std::convert::From<TaskFailure> for proto::TaskFailure {
         }
     }
 }
+
+impl std::convert::TryFrom<proto::TaskResult> for TaskResult {
+    type Error = Error;
+    fn try_from(proto: proto::TaskResult) -> Result<Self> {
+        let task_result = match proto.result {
+            Some(proto_result) => match proto_result {
+                proto::task_result::Result::Ok(task_outputs) => {
+                    let outputs_info = task_outputs.try_into()?;
+                    TaskResult::Ok(outputs_info)
+                }
+                proto::task_result::Result::Err(task_failure) => {
+                    let failure_info = task_failure.try_into()?;
+                    TaskResult::Err(failure_info)
+                }
+            },
+            None => TaskResult::NotReady,
+        };
+        Ok(task_result)
+    }
+}
+
+impl std::convert::From<TaskResult> for proto::TaskResult {
+    fn from(result: TaskResult) -> Self {
+        let opt_result = match result {
+            TaskResult::Ok(outputs) => Some(proto::task_result::Result::Ok(outputs.into())),
+            TaskResult::Err(failure) => Some(proto::task_result::Result::Err(failure.into())),
+            TaskResult::NotReady => None,
+        };
+
+        proto::TaskResult { result: opt_result }
+    }
+}
diff --git a/services/proto/src/teaclave_frontend_service.rs b/services/proto/src/teaclave_frontend_service.rs
index 994a010..e06893c 100644
--- a/services/proto/src/teaclave_frontend_service.rs
+++ b/services/proto/src/teaclave_frontend_service.rs
@@ -27,7 +27,7 @@ use std::prelude::v1::*;
 use teaclave_rpc::into_request;
 use teaclave_types::{
     Executor, ExecutorType, ExternalID, FileCrypto, Function, FunctionArguments, FunctionInput,
-    FunctionOutput, OwnerList, TaskStatus, UserID, UserList,
+    FunctionOutput, OwnerList, TaskResult, TaskStatus, UserID, UserList,
 };
 use url::Url;
 use uuid::Uuid;
@@ -428,9 +428,8 @@ pub struct GetTaskResponse {
     pub approved_users: UserList,
     pub input_map: HashMap<String, ExternalID>,
     pub output_map: HashMap<String, ExternalID>,
-    pub return_value: Vec<u8>,
-    pub output_file_hash: HashMap<String, String>,
     pub status: TaskStatus,
+    pub result: TaskResult,
 }
 
 #[into_request(TeaclaveManagementRequest::AssignData)]
@@ -1062,6 +1061,7 @@ impl std::convert::TryFrom<proto::GetTaskResponse> for GetTaskResponse {
         let status = i32_to_task_status(proto.status)?;
         let function_id = proto.function_id.try_into()?;
         let task_id = proto.task_id.try_into()?;
+        let result = proto.result.try_into()?;
 
         let ret = Self {
             task_id,
@@ -1075,9 +1075,8 @@ impl std::convert::TryFrom<proto::GetTaskResponse> for GetTaskResponse {
             approved_users: UserList::new(proto.approved_users),
             input_map,
             output_map,
-            return_value: proto.return_value,
-            output_file_hash: proto.output_file_hash,
             status,
+            result,
         };
 
         Ok(ret)
@@ -1104,9 +1103,8 @@ impl From<GetTaskResponse> for proto::GetTaskResponse {
             approved_users: response.approved_users.into(),
             input_map,
             output_map,
-            return_value: response.return_value,
-            output_file_hash: response.output_file_hash,
             status,
+            result: Some(response.result.into()),
         }
     }
 }
diff --git a/services/proto/src/teaclave_scheduler_service.rs b/services/proto/src/teaclave_scheduler_service.rs
index 7d7603d..3993940 100644
--- a/services/proto/src/teaclave_scheduler_service.rs
+++ b/services/proto/src/teaclave_scheduler_service.rs
@@ -30,7 +30,7 @@ pub use proto::TeaclaveSchedulerClient;
 pub use proto::TeaclaveSchedulerRequest;
 pub use proto::TeaclaveSchedulerResponse;
 use teaclave_rpc::into_request;
-use teaclave_types::{StagedTask, TaskFailure, TaskOutputs, TaskStatus};
+use teaclave_types::{StagedTask, TaskFailure, TaskOutputs, TaskResult, TaskStatus};
 use uuid::Uuid;
 
 #[into_request(TeaclaveSchedulerRequest::Subscribe)]
@@ -56,8 +56,6 @@ impl PullTaskResponse {
     }
 }
 
-pub type TaskResult = std::result::Result<TaskOutputs, TaskFailure>;
-
 #[into_request(TeaclaveSchedulerRequest::UpdateTaskResult)]
 pub struct UpdateTaskResultRequest {
     pub task_id: Uuid,
@@ -175,24 +173,9 @@ impl std::convert::From<PullTaskResponse> for proto::PullTaskResponse {
 impl std::convert::TryFrom<proto::UpdateTaskResultRequest> for UpdateTaskResultRequest {
     type Error = Error;
     fn try_from(proto: proto::UpdateTaskResultRequest) -> Result<Self> {
-        let task_id = Uuid::parse_str(&proto.task_id)?;
-        let proto_result = proto
-            .task_result
-            .ok_or_else(|| anyhow::anyhow!("task result is empty"))?;
-        let task_result = match proto_result {
-            proto::update_task_result_request::TaskResult::Ok(task_outputs) => {
-                let outputs_info = task_outputs.try_into()?;
-                Ok(outputs_info)
-            }
-            proto::update_task_result_request::TaskResult::Err(task_failure) => {
-                let failure_info = task_failure.try_into()?;
-                Err(failure_info)
-            }
-        };
-
         let ret = Self {
-            task_id,
-            task_result,
+            task_id: Uuid::parse_str(&proto.task_id)?,
+            task_result: proto.result.try_into()?,
         };
         Ok(ret)
     }
@@ -200,18 +183,9 @@ impl std::convert::TryFrom<proto::UpdateTaskResultRequest> for UpdateTaskResultR
 
 impl std::convert::From<UpdateTaskResultRequest> for proto::UpdateTaskResultRequest {
     fn from(req: UpdateTaskResultRequest) -> Self {
-        let task_result = match req.task_result {
-            Ok(task_outputs) => {
-                proto::update_task_result_request::TaskResult::Ok(task_outputs.into())
-            }
-            Err(task_failure) => {
-                proto::update_task_result_request::TaskResult::Err(task_failure.into())
-            }
-        };
-
         proto::UpdateTaskResultRequest {
             task_id: req.task_id.to_string(),
-            task_result: Some(task_result),
+            result: Some(req.task_result.into()),
         }
     }
 }
diff --git a/services/scheduler/enclave/src/service.rs b/services/scheduler/enclave/src/service.rs
index a23743f..49baf50 100644
--- a/services/scheduler/enclave/src/service.rs
+++ b/services/scheduler/enclave/src/service.rs
@@ -175,13 +175,7 @@ impl TeaclaveScheduler for TeaclaveSchedulerService {
     ) -> TeaclaveServiceResponseResult<UpdateTaskResultResponse> {
         let request = request.message;
         let mut task = self.get_task(&request.task_id.to_string())?;
-        match request.task_result {
-            Ok(result) => {
-                task.return_value = Some(result.return_value);
-                task.output_file_hash = result.output_file_hash;
-            }
-            Err(failure) => unimplemented!(),
-        };
+        task.result = request.task_result;
 
         // Updating task result means we have finished execution
         task.status = TaskStatus::Finished;
diff --git a/tests/functional/enclave/src/end_to_end/mesapy_echo.rs b/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
index fafde87..b4fe09a 100644
--- a/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
+++ b/tests/functional/enclave/src/end_to_end/mesapy_echo.rs
@@ -63,28 +63,12 @@ def entrypoint(argv):
     log::info!("Assign data: {:?}", response);
 
     // Approve Task
-    let request = ApproveTaskRequest::new(task_id.clone());
-    let response = client.approve_task(request).unwrap();
-
-    log::info!("Approve task: {:?}", response);
+    approve_task(&mut client, &task_id);
 
     // Invoke Task
-    let request = InvokeTaskRequest::new(task_id.clone());
-    let response = client.invoke_task(request).unwrap();
-
-    log::info!("Invoke task: {:?}", response);
+    invoke_task(&mut client, &task_id);
 
     // Get Task
-    loop {
-        let request = GetTaskRequest::new(task_id.clone());
-        let response = client.get_task(request).unwrap();
-        log::info!("Get task: {:?}", response);
-        std::thread::sleep(std::time::Duration::from_secs(1));
-        if response.status != TaskStatus::Running {
-            let ret_val = String::from_utf8(response.return_value).unwrap();
-            log::info!("Task returns: {:?}", ret_val);
-            assert_eq!(&ret_val, "Hello From Teaclave!");
-            break;
-        }
-    }
+    let ret_val = get_task_until(&mut client, &task_id, TaskStatus::Finished);
+    assert_eq!(&ret_val, "Hello From Teaclave!");
 }
diff --git a/tests/functional/enclave/src/end_to_end/mod.rs b/tests/functional/enclave/src/end_to_end/mod.rs
index 560a280..755b61f 100644
--- a/tests/functional/enclave/src/end_to_end/mod.rs
+++ b/tests/functional/enclave/src/end_to_end/mod.rs
@@ -44,3 +44,44 @@ fn setup() {
         create_authentication_api_client(shared_enclave_info(), AUTH_SERVICE_ADDR).unwrap();
     register_new_account(&mut api_client, USERNAME, PASSWORD).unwrap();
 }
+
+fn get_task_until(
+    client: &mut TeaclaveFrontendClient,
+    task_id: &ExternalID,
+    status: TaskStatus,
+) -> String {
+    loop {
+        let request = GetTaskRequest::new(task_id.clone());
+        let response = client.get_task(request).unwrap();
+        log::info!("Get task: {:?}", response);
+
+        std::thread::sleep(std::time::Duration::from_secs(1));
+
+        if response.status == status {
+            match response.result {
+                TaskResult::Ok(outputs) => {
+                    let ret_val = String::from_utf8(outputs.return_value).unwrap();
+                    log::info!("Task returns: {:?}", ret_val);
+                    return ret_val;
+                }
+                TaskResult::Err(failure) => {
+                    log::error!("Task failed, reason: {:?}", failure);
+                    return failure.to_string();
+                }
+                TaskResult::NotReady => unreachable!(),
+            }
+        }
+    }
+}
+
+fn approve_task(client: &mut TeaclaveFrontendClient, task_id: &ExternalID) {
+    let request = ApproveTaskRequest::new(task_id.clone());
+    let response = client.approve_task(request).unwrap();
+    log::info!("Approve task: {:?}", response);
+}
+
+fn invoke_task(client: &mut TeaclaveFrontendClient, task_id: &ExternalID) {
+    let request = InvokeTaskRequest::new(task_id.clone());
+    let response = client.invoke_task(request).unwrap();
+    log::info!("Invoke task: {:?}", response);
+}
diff --git a/tests/functional/enclave/src/end_to_end/native_echo.rs b/tests/functional/enclave/src/end_to_end/native_echo.rs
index e844930..ccf908d 100644
--- a/tests/functional/enclave/src/end_to_end/native_echo.rs
+++ b/tests/functional/enclave/src/end_to_end/native_echo.rs
@@ -56,28 +56,12 @@ pub fn test_echo_task_success() {
     log::info!("Assign data: {:?}", response);
 
     // Approve Task
-    let request = ApproveTaskRequest::new(task_id.clone());
-    let response = client.approve_task(request).unwrap();
-
-    log::info!("Approve task: {:?}", response);
+    approve_task(&mut client, &task_id);
 
     // Invoke Task
-    let request = InvokeTaskRequest::new(task_id.clone());
-    let response = client.invoke_task(request).unwrap();
-
-    log::info!("Invoke task: {:?}", response);
+    invoke_task(&mut client, &task_id);
 
     // Get Task
-    loop {
-        let request = GetTaskRequest::new(task_id.clone());
-        let response = client.get_task(request).unwrap();
-        log::info!("Get task: {:?}", response);
-        std::thread::sleep(std::time::Duration::from_secs(1));
-        if response.status != TaskStatus::Running {
-            let ret_val = String::from_utf8(response.return_value).unwrap();
-            log::info!("Task returns: {:?}", ret_val);
-            assert_eq!(&ret_val, "Hello From Teaclave!");
-            break;
-        }
-    }
+    let ret_val = get_task_until(&mut client, &task_id, TaskStatus::Finished);
+    assert_eq!(&ret_val, "Hello From Teaclave!");
 }
diff --git a/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs b/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs
index 0affbdf..3b1f5c0 100644
--- a/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs
+++ b/tests/functional/enclave/src/end_to_end/native_gbdt_training.rs
@@ -18,6 +18,23 @@
 use super::*;
 use teaclave_crypto::TeaclaveFile128Key;
 
+pub fn test_gbdt_training_task() {
+    let mut client = authorized_frontend_client();
+    let function_id = register_gbdt_function(&mut client);
+    let training_data_id = register_input_file(&mut client);
+
+    let crypto = TeaclaveFile128Key::random();
+    let output_model_id = register_output_file(&mut client, crypto);
+
+    let task_id = create_gbdt_training_task(&mut client, &function_id);
+    assign_data_to_task(&mut client, &task_id, training_data_id, output_model_id);
+    approve_task(&mut client, &task_id);
+    invoke_task(&mut client, &task_id);
+
+    let ret_val = get_task_until(&mut client, &task_id, TaskStatus::Finished);
+    assert_eq!(&ret_val, "Trained 120 lines of data.");
+}
+
 // Authenticate user before talking to frontend service
 fn authorized_frontend_client() -> TeaclaveFrontendClient {
     let mut api_client =
@@ -125,52 +142,3 @@ fn assign_data_to_task(
 
     log::info!("Assign data: {:?}", response);
 }
-
-fn approve_task(client: &mut TeaclaveFrontendClient, task_id: &ExternalID) {
-    let request = ApproveTaskRequest::new(task_id.clone());
-    let response = client.approve_task(request).unwrap();
-    log::info!("Approve task: {:?}", response);
-}
-
-fn invoke_task(client: &mut TeaclaveFrontendClient, task_id: &ExternalID) {
-    let request = InvokeTaskRequest::new(task_id.clone());
-    let response = client.invoke_task(request).unwrap();
-    log::info!("Invoke task: {:?}", response);
-}
-
-fn get_task_until(
-    client: &mut TeaclaveFrontendClient,
-    task_id: &ExternalID,
-    status: TaskStatus,
-) -> String {
-    loop {
-        let request = GetTaskRequest::new(task_id.clone());
-        let response = client.get_task(request).unwrap();
-        log::info!("Get task: {:?}", response);
-
-        std::thread::sleep(std::time::Duration::from_secs(1));
-
-        if response.status == status {
-            let ret_val = String::from_utf8(response.return_value).unwrap();
-            log::info!("Task returns: {:?}", ret_val);
-            return ret_val;
-        }
-    }
-}
-
-pub fn test_gbdt_training_task() {
-    let mut client = authorized_frontend_client();
-    let function_id = register_gbdt_function(&mut client);
-    let training_data_id = register_input_file(&mut client);
-
-    let crypto = TeaclaveFile128Key::random();
-    let output_model_id = register_output_file(&mut client, crypto);
-
-    let task_id = create_gbdt_training_task(&mut client, &function_id);
-    assign_data_to_task(&mut client, &task_id, training_data_id, output_model_id);
-    approve_task(&mut client, &task_id);
-    invoke_task(&mut client, &task_id);
-
-    let ret_val = get_task_until(&mut client, &task_id, TaskStatus::Finished);
-    assert_eq!(&ret_val, "Trained 120 lines of data.");
-}
diff --git a/tests/functional/enclave/src/execution_service.rs b/tests/functional/enclave/src/execution_service.rs
index 0f8d68d..e0306a0 100644
--- a/tests/functional/enclave/src/execution_service.rs
+++ b/tests/functional/enclave/src/execution_service.rs
@@ -60,7 +60,7 @@ fn test_execute_function() {
     let get_response = storage_client.get(get_request).unwrap();
     let updated_task = Task::from_slice(get_response.value.as_slice()).unwrap();
     assert_eq!(
-        updated_task.return_value.unwrap(),
+        updated_task.result.unwrap().return_value,
         b"Hello, Teaclave Tests!"
     );
 }
diff --git a/types/src/task.rs b/types/src/task.rs
index 68ec777..98638c9 100644
--- a/types/src/task.rs
+++ b/types/src/task.rs
@@ -18,7 +18,7 @@
 use crate::FunctionArguments;
 use crate::Storable;
 use crate::*;
-use anyhow::{anyhow, bail, ensure, Result};
+use anyhow::{anyhow, bail, ensure, Error, Result};
 use serde::{Deserialize, Serialize};
 use std::collections::{HashMap, HashSet};
 use std::convert::TryInto;
@@ -160,6 +160,20 @@ pub struct TaskFailure {
     pub reason: String,
 }
 
+impl TaskFailure {
+    pub fn new(reason: impl ToString) -> Self {
+        TaskFailure {
+            reason: reason.to_string(),
+        }
+    }
+}
+
+impl std::fmt::Display for TaskFailure {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "TaskFailure {}", self.reason)
+    }
+}
+
 #[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
 pub struct ExternalID {
     pub prefix: String,
@@ -214,6 +228,64 @@ impl std::convert::TryFrom<String> for ExternalID {
     }
 }
 
+#[derive(Debug, Deserialize, Serialize)]
+pub enum TaskResult {
+    NotReady,
+    Ok(TaskOutputs),
+    Err(TaskFailure),
+}
+
+#[cfg(test_mode)]
+impl TaskResult {
+    pub fn unwrap(self) -> TaskOutputs {
+        match self {
+            TaskResult::Ok(t) => t,
+            TaskResult::Err(e) => {
+                panic!("called `TaskResult::unwrap()` on an `Err` value: {:?}", &e)
+            }
+            TaskResult::NotReady => panic!("called `TaskResult::unwrap()` on NotReady case"),
+        }
+    }
+}
+
+impl Default for TaskResult {
+    fn default() -> Self {
+        TaskResult::NotReady
+    }
+}
+
+// This is intended for proto::TaskResult field
+// Since proto::TaskResult is a wrapper of One-Of keywords,
+// it is always converted to an Option<proto::TaskResult>
+// when referenced in a request/response structure.
+impl<T> std::convert::TryFrom<Option<T>> for TaskResult
+where
+    T: TryInto<TaskResult, Error = Error>,
+{
+    type Error = Error;
+    fn try_from(option: Option<T>) -> Result<Self> {
+        let ret = match option {
+            Some(result) => result.try_into()?,
+            None => unreachable!(),
+        };
+        Ok(ret)
+    }
+}
+
+impl<T, E> std::convert::From<TaskResult> for Option<std::result::Result<T, E>>
+where
+    T: From<TaskOutputs>,
+    E: From<TaskFailure>,
+{
+    fn from(task_result: TaskResult) -> Option<std::result::Result<T, E>> {
+        match task_result {
+            TaskResult::Ok(t) => Some(Ok(t.into())),
+            TaskResult::Err(e) => Some(Err(e.into())),
+            TaskResult::NotReady => None,
+        }
+    }
+}
+
 const TASK_PREFIX: &str = "task";
 
 #[derive(Debug, Default, Deserialize, Serialize)]
@@ -230,8 +302,7 @@ pub struct Task {
     pub approved_users: UserList,
     pub input_map: HashMap<String, ExternalID>,
     pub output_map: HashMap<String, ExternalID>,
-    pub return_value: Option<Vec<u8>>,
-    pub output_file_hash: HashMap<String, String>,
+    pub result: TaskResult,
     pub status: TaskStatus,
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org