我是Rust的初學者。如何通過Rest api實現一個長時間運行的進程,在Rust中可以使用?
我有一個長期運行的IO綁定進程,我想通過REST API產生和監視。我選擇了Iron,繼此tutorial。監測意味着取得進展和最終結果。
當我產卵時,我給它一個id並將該id映射到可以獲取進度的資源。我不必確切地瞭解進展;我可以從5秒前報告進度。
我的第一次嘗試是有一個通道,通過它發送進度請求並接收狀態。我卡在存儲接收器的地方,因爲在我的理解中,它只屬於一個線程。我想把它放在請求的上下文中,但這不會工作,因爲有不同的線程處理後續請求。
在Rust裏做到這一點的慣用方法是什麼?
我有一個sample project。
後來編輯:
這裏是一個自包含的例子如下樣品原則回答,即地圖,每個線程更新其進度:
extern crate iron;
extern crate router;
extern crate rustc_serialize;
use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json;
use std::io::Read;
use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;
use std::collections::HashMap;
#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub struct Status {
pub progress: u64,
pub context: String
}
#[derive(RustcEncodable, RustcDecodable)]
struct StartTask {
id: u64
}
fn start_process(status: Arc<Mutex<HashMap<u64, Status>>>, task_id: u64) {
let c = status.clone();
thread::spawn(move || {
for i in 1..100 {
{
let m = &mut c.lock().unwrap();
m.insert(task_id, Status{ progress: i, context: "in progress".to_string()});
}
thread::sleep(Duration::from_secs(1));
}
let m = &mut c.lock().unwrap();
m.insert(task_id, Status{ progress: 100, context: "done".to_string()});
});
}
fn main() {
let status: Arc<Mutex<HashMap<u64, Status>>> = Arc::new(Mutex::new(HashMap::new()));
let status_clone: Arc<Mutex<HashMap<u64, Status>>> = status.clone();
let mut router = Router::new();
router.get("/:taskId", move |r: &mut Request| task_status(r, &status.lock().unwrap()));
router.post("/start", move |r: &mut Request|
start_task(r, status_clone.clone()));
fn task_status(req: &mut Request, statuses: & HashMap<u64,Status>) -> IronResult<Response> {
let ref task_id = req.extensions.get::<Router>().unwrap().find("taskId").unwrap_or("/").parse::<u64>().unwrap();
let payload = json::encode(&statuses.get(&task_id)).unwrap();
Ok(Response::with((status::Ok, payload)))
}
// Receive a message by POST and play it back.
fn start_task(request: &mut Request, statuses: Arc<Mutex<HashMap<u64, Status>>>) -> IronResult<Response> {
let mut payload = String::new();
request.body.read_to_string(&mut payload).unwrap();
let task_start_request: StartTask = json::decode(&payload).unwrap();
start_process(statuses, task_start_request.id);
Ok(Response::with((status::Ok, json::encode(&task_start_request).unwrap())))
}
Iron::new(router).http("localhost:3000").unwrap();
}
謝謝你的回答。正如你在我的更新問題中看到的那樣,我最終做的就是這樣。我最初的想法與演員類似。我在Scala中用演員完成了一些類似的事情,開始一個長時間運行的過程意味着產生一個演員(實際上2,做一個工作,另一個保持進度),我在隨後的進度報告請求上查詢。 –