@@ -2,17 +2,18 @@ use std::collections::HashMap;
2
2
use std:: convert:: { TryFrom , TryInto } ;
3
3
4
4
use std:: str:: from_utf8;
5
+ use std:: time:: SystemTime ;
5
6
6
- use tokio :: sync :: { broadcast , mpsc } ;
7
- use worker_message:: { CoordinatorMessage , ExecuteOutput } ;
7
+
8
+ use worker_message:: { ExecuteOutput , Job } ;
8
9
9
10
use crate :: sandbox:: {
10
11
self , Channel , CompileRequest , CrateType , Edition , ExecuteRequest , FormatRequest , Mode ,
11
12
} ;
12
13
use crate :: { parse_channel, parse_crate_type, parse_edition, parse_mode, parse_target, Error } ;
13
14
14
15
struct JobBatch {
15
- jobs : Vec < worker_message :: Request > ,
16
+ job : Job ,
16
17
extra : serde_json:: Value
17
18
}
18
19
@@ -21,14 +22,14 @@ fn split_request(req: WSRequest) -> JobBatch {
21
22
WSRequest :: Compile ( req) => {
22
23
let ( req, extra) = req. try_into ( ) . unwrap ( ) ;
23
24
JobBatch {
24
- jobs : compile_request_to_batch ( req) ,
25
+ job : worker_message :: Job { reqs : compile_request_to_batch ( req) } ,
25
26
extra
26
27
}
27
28
}
28
29
WSRequest :: Format ( req) => {
29
30
let ( req, extra) = req. try_into ( ) . unwrap ( ) ;
30
31
JobBatch {
31
- jobs : format_request_to_batch ( req) ,
32
+ job : worker_message :: Job { reqs : format_request_to_batch ( req) } ,
32
33
extra
33
34
}
34
35
}
@@ -356,17 +357,16 @@ fn worker_response_to_websocket_response(resp: BatchResponse) -> WSResponse {
356
357
// }
357
358
// response
358
359
// }
359
-
360
- async fn work (
361
- req : worker_message:: Request ,
362
- sender : & mpsc:: Sender < CoordinatorMessage > ,
363
- receiver : & mut broadcast:: Receiver < worker_message:: Response > ,
364
- ) -> worker_message:: Response {
365
- let coordinator_msg = CoordinatorMessage :: Request ( 0 , req) ;
366
- sender. send ( coordinator_msg) . await . unwrap ( ) ;
367
- receiver. recv ( ) . await . unwrap ( )
360
+ //
361
+ // It's safe unless a leap second happens.
362
+ fn now_as_uid ( ) -> u128 {
363
+ SystemTime :: now ( )
364
+ . duration_since ( SystemTime :: UNIX_EPOCH )
365
+ . unwrap ( )
366
+ . as_nanos ( )
368
367
}
369
368
369
+
370
370
#[ derive( serde:: Deserialize ) ]
371
371
#[ serde( rename_all = "camelCase" ) ]
372
372
struct WSExecuteRequest {
@@ -566,6 +566,7 @@ enum WSResponse {
566
566
#[ cfg( test) ]
567
567
mod tests {
568
568
569
+ use std:: collections:: HashMap ;
569
570
use std:: process:: Stdio ;
570
571
571
572
use std:: sync:: Arc ;
@@ -574,17 +575,17 @@ mod tests {
574
575
575
576
const WORKER_FILEPATH : & str = "../worker-message/target/debug/worker" ;
576
577
use crate :: coordinator:: {
577
- split_request, work , worker_response_to_websocket_response, BatchResponse ,
578
- PlaygroundMessage , ResponseKind , WSMessage , WSRequest , WSResponse ,
578
+ split_request, worker_response_to_websocket_response, BatchResponse ,
579
+ PlaygroundMessage , ResponseKind , WSMessage , WSRequest , WSResponse , now_as_uid ,
579
580
} ;
580
581
581
582
use serde_json:: json;
582
583
use tokio:: io:: { AsyncReadExt , AsyncWriteExt } ;
583
584
use tokio:: process:: { ChildStdin , ChildStdout , Command } ;
584
- use tokio:: sync:: { broadcast , mpsc } ;
585
+ use tokio:: sync:: { mpsc , oneshot } ;
585
586
use tokio:: task:: JoinHandle ;
586
587
use tokio:: time:: error:: Elapsed ;
587
- use worker_message:: { CoordinatorMessage , WorkerMessage } ;
588
+ use worker_message:: { CoordinatorMessage , WorkerMessage , JobReport } ;
588
589
589
590
use super :: { WSCompileRequest , WSFormatRequest } ;
590
591
@@ -717,8 +718,9 @@ mod tests {
717
718
worker_sender : mpsc:: Sender < CoordinatorMessage > ,
718
719
mut worker_receiver : mpsc:: Receiver < WorkerMessage > ,
719
720
) {
720
- let mut current_task: Option < JoinHandle < ( ) > > = None ;
721
- let ( worker_response_tx, _worker_response_rx) = broadcast:: channel ( 32 ) ;
721
+ let mut worker_response_senders = HashMap :: new ( ) ;
722
+ let ( worker_response_sender_tx, mut worker_response_sender_rx) = mpsc:: channel ( 32 ) ;
723
+ let mut current_job: Option < JoinHandle < ( ) > > = None ;
722
724
loop {
723
725
tokio:: select! {
724
726
ws_request = ws_receiver. recv( ) => {
@@ -730,54 +732,60 @@ mod tests {
730
732
let ws_msg = serde_json:: from_str( & txt) . expect( "Failed to deserialize websocket message from json string" ) ;
731
733
match ws_msg {
732
734
WSMessage :: Request ( ws_request) => {
733
- // Abort current task .
735
+ // Abort current job .
734
736
// Lower request into low-level operations.
735
737
// Execute operations in sequence until a failure is reached.
736
- if let Some ( task ) = current_task {
737
- task . abort( ) ;
738
+ if let Some ( job ) = current_job {
739
+ job . abort( ) ;
738
740
}
739
- let mut worker_response_rx = worker_response_tx. subscribe( ) ;
740
741
let worker_sender = worker_sender. clone( ) ;
741
742
let ws_sender = ws_sender. clone( ) ;
742
- let kind = ResponseKind :: kind( & ws_request) ;
743
- let batch = split_request( ws_request) ;
744
- let jobs = batch. jobs;
745
- let extra = batch. extra;
746
- current_task = Some ( tokio:: spawn( async move {
747
- assert!( jobs. len( ) != 0 ) ;
748
- let mut responses = Vec :: with_capacity( jobs. len( ) ) ;
749
- for job in jobs {
750
- let resp = work( job, & worker_sender, & mut worker_response_rx) . await ;
751
- if !resp. is_ok( ) {
752
- responses. push( resp) ;
753
- break ;
754
- }
755
- responses. push( resp) ;
756
- }
743
+ let worker_response_sender_tx = worker_response_sender_tx. clone( ) ;
744
+ current_job = Some ( tokio:: spawn( async move {
745
+ let kind = ResponseKind :: kind( & ws_request) ;
746
+ let batch = split_request( ws_request) ;
747
+ let job = batch. job;
748
+ let extra = batch. extra;
749
+ let id = now_as_uid( ) ;
750
+ let ( resp_tx, resp_rx) = oneshot:: channel( ) ;
751
+ worker_response_sender_tx. send( ( id, resp_tx) ) . await . unwrap( ) ;
752
+ let coordinator_msg = CoordinatorMessage :: Request ( id, job) ;
753
+ worker_sender. send( coordinator_msg) . await . unwrap( ) ;
754
+ let job_report: JobReport = resp_rx. await . unwrap( ) ;
755
+ let worker_response = job_report. resps;
757
756
let batch_response = BatchResponse {
758
757
kind,
759
- responses,
758
+ responses: worker_response ,
760
759
extra
761
760
} ;
762
761
let ws_response = worker_response_to_websocket_response( batch_response) ;
763
762
ws_sender. send( serde_json:: to_string( & PlaygroundMessage :: Response ( ws_response) ) . expect( "Failed to serialize websocket response" ) ) . await . expect( "WebSocket failed to send response to user" ) ;
764
763
} ) ) ;
764
+
765
765
}
766
766
WSMessage :: StdinPacket ( packet) => { }
767
767
}
768
768
}
769
769
}
770
770
} ,
771
+ worker_response_sender = worker_response_sender_rx. recv( ) => {
772
+ if let Some ( ( uid, resp_tx) ) = worker_response_sender {
773
+ worker_response_senders. insert( uid, resp_tx) ;
774
+ } else {
775
+ break ;
776
+ }
777
+ } ,
771
778
worker_msg = worker_receiver. recv( ) => {
772
779
match worker_msg {
773
780
None => {
774
781
break ;
775
782
}
776
783
Some ( msg) => {
777
784
match msg {
778
- WorkerMessage :: Response ( uid, resp) => {
779
- // TODO: drop response that belongs to aborted job.
780
- worker_response_tx. send( resp) . unwrap( ) ;
785
+ WorkerMessage :: Response ( id, resp) => {
786
+ if let Some ( tx) = worker_response_senders. remove( & id) {
787
+ tx. send( resp) . unwrap( ) ;
788
+ }
781
789
}
782
790
WorkerMessage :: StdoutPacket ( pid, packet) => { }
783
791
WorkerMessage :: StderrPacket ( pid, packet) => { }
@@ -791,12 +799,12 @@ mod tests {
791
799
792
800
async fn setup_coordinator ( ) -> ( mpsc:: Sender < String > , mpsc:: Receiver < String > ) {
793
801
let ( worker_sender, worker_receiver) = make_worker_channel ( ) . await ;
794
- let ( tx , ws_receiver) = mpsc:: channel ( 32 ) ;
795
- let ( ws_sender, rx ) = mpsc:: channel ( 32 ) ;
802
+ let ( client_tx , ws_receiver) = mpsc:: channel ( 32 ) ;
803
+ let ( ws_sender, client_rx ) = mpsc:: channel ( 32 ) ;
796
804
tokio:: spawn ( async move {
797
805
pair_websocket_worker ( ws_sender, ws_receiver, worker_sender, worker_receiver) . await ;
798
806
} ) ;
799
- ( tx , rx )
807
+ ( client_tx , client_rx )
800
808
}
801
809
802
810
async fn check_websocket_request_response (
0 commit comments