@@ -13,9 +13,10 @@ use std::{
13
13
atomic:: { AtomicUsize , Ordering } ,
14
14
Mutex ,
15
15
} ,
16
- task:: { ready , Poll } ,
16
+ task:: Poll ,
17
17
} ;
18
18
19
+ use cancel_safe_futures:: coop_cancel;
19
20
use debug_ignore:: DebugIgnore ;
20
21
use derive_where:: derive_where;
21
22
use futures:: { future:: BoxFuture , prelude:: * } ;
@@ -74,8 +75,8 @@ pub struct UpdateEngine<'a, S: StepSpec> {
74
75
sender : mpsc:: Sender < Event < S > > ,
75
76
76
77
// This is set to None in Self::execute.
77
- abort_sender : Option < mpsc :: UnboundedSender < AbortMessage > > ,
78
- abort_receiver : mpsc :: UnboundedReceiver < AbortMessage > ,
78
+ canceler : Option < coop_cancel :: Canceler < String > > ,
79
+ cancel_receiver : coop_cancel :: Receiver < String > ,
79
80
80
81
// This is a mutex to allow borrows to steps to be held by both
81
82
// ComponentRegistrar and NewStep at the same time. (This could also be a
@@ -90,16 +91,16 @@ impl<'a, S: StepSpec + 'a> UpdateEngine<'a, S> {
90
91
/// Creates a new `UpdateEngine`.
91
92
pub fn new ( log : & slog:: Logger , sender : mpsc:: Sender < Event < S > > ) -> Self {
92
93
let execution_id = ExecutionId ( Uuid :: new_v4 ( ) ) ;
93
- let ( abort_sender , abort_receiver ) = mpsc :: unbounded_channel ( ) ;
94
+ let ( canceler , cancel_receiver ) = coop_cancel :: new_pair ( ) ;
94
95
Self {
95
96
log : log. new ( slog:: o!(
96
97
"component" => "UpdateEngine" ,
97
98
"execution_id" => format!( "{execution_id}" ) ,
98
99
) ) ,
99
100
execution_id : ExecutionId ( Uuid :: new_v4 ( ) ) ,
100
101
sender,
101
- abort_sender : Some ( abort_sender ) ,
102
- abort_receiver ,
102
+ canceler : Some ( canceler ) ,
103
+ cancel_receiver ,
103
104
steps : Default :: default ( ) ,
104
105
}
105
106
}
@@ -156,8 +157,8 @@ impl<'a, S: StepSpec + 'a> UpdateEngine<'a, S> {
156
157
/// An abort handle can be used to forcibly cancel update engine executions.
157
158
pub fn abort_handle ( & self ) -> AbortHandle {
158
159
AbortHandle {
159
- abort_sender : self
160
- . abort_sender
160
+ canceler : self
161
+ . canceler
161
162
. as_ref ( )
162
163
. expect ( "abort_sender should always be present" )
163
164
. clone ( ) ,
@@ -169,11 +170,11 @@ impl<'a, S: StepSpec + 'a> UpdateEngine<'a, S> {
169
170
/// This returns an `ExecutionHandle`, which needs to be awaited on to drive
170
171
/// the engine forward.
171
172
pub fn execute ( mut self ) -> ExecutionHandle < ' a , S > {
172
- let abort_sender = self
173
- . abort_sender
173
+ let canceler = self
174
+ . canceler
174
175
. take ( )
175
176
. expect ( "execute is the only function which does this" ) ;
176
- let abort_handle = AbortHandle { abort_sender } ;
177
+ let abort_handle = AbortHandle { canceler } ;
177
178
178
179
let engine_fut = self . execute_impl ( ) . boxed ( ) ;
179
180
@@ -278,7 +279,7 @@ impl<'a, S: StepSpec + 'a> UpdateEngine<'a, S> {
278
279
279
280
let ( mut step_res, mut reporter) = first_step
280
281
. exec
281
- . execute ( & self . log , step_exec_cx, & mut self . abort_receiver )
282
+ . execute ( & self . log , step_exec_cx, & mut self . cancel_receiver )
282
283
. await ?;
283
284
284
285
// Now run all remaining steps.
@@ -299,7 +300,7 @@ impl<'a, S: StepSpec + 'a> UpdateEngine<'a, S> {
299
300
300
301
( step_res, reporter) = step
301
302
. exec
302
- . execute ( & self . log , step_exec_cx, & mut self . abort_receiver )
303
+ . execute ( & self . log , step_exec_cx, & mut self . cancel_receiver )
303
304
. await ?;
304
305
}
305
306
@@ -328,10 +329,15 @@ impl<'a, S: StepSpec> ExecutionHandle<'a, S> {
328
329
/// This sends the message immediately, and returns a future that can be
329
330
/// optionally waited against to block until the abort is processed.
330
331
///
331
- /// If this engine is still running, it is immediately aborted. The engine
332
- /// sends an `ExecutionAborted` message over the wire, and an
332
+ /// If this engine is still running, it is aborted at the next await point.
333
+ /// The engine sends an `ExecutionAborted` message over the wire, and an
333
334
/// `ExecutionError::Aborted` is returned.
334
- pub fn abort ( & self , message : impl Into < String > ) -> AbortWaiter {
335
+ ///
336
+ /// Returns `Err(message)` if the engine has already completed execution.
337
+ pub fn abort (
338
+ & self ,
339
+ message : impl Into < String > ,
340
+ ) -> Result < AbortWaiter , String > {
335
341
self . abort_handle . abort ( message. into ( ) )
336
342
}
337
343
@@ -357,9 +363,7 @@ impl<'a, S: StepSpec> Future for ExecutionHandle<'a, S> {
357
363
/// An abort handle, used to forcibly cancel update engine executions.
358
364
#[ derive( Clone , Debug ) ]
359
365
pub struct AbortHandle {
360
- // This is an unbounded sender to make Self::abort not async. In general we
361
- // don't expect more than one message to ever be sent on this channel.
362
- abort_sender : mpsc:: UnboundedSender < AbortMessage > ,
366
+ canceler : coop_cancel:: Canceler < String > ,
363
367
}
364
368
365
369
impl AbortHandle {
@@ -368,15 +372,17 @@ impl AbortHandle {
368
372
/// This sends the message immediately, and returns a future that can be
369
373
/// optionally waited against to block until the abort is processed.
370
374
///
371
- /// If this engine is still running, it is immediately aborted. The engine
372
- /// sends an `ExecutionAborted` message over the wire, and an
375
+ /// If this engine is still running, it is aborted at the next await point.
376
+ /// The engine sends an `ExecutionAborted` message over the wire, and an
373
377
/// `ExecutionError::Aborted` is returned.
374
- pub fn abort ( & self , message : impl Into < String > ) -> AbortWaiter {
375
- // Ignore errors here because if the receiver is closed, the engine has
376
- // completed (or failed) execution.
377
- let ( message, processed_receiver) = AbortMessage :: new ( message. into ( ) ) ;
378
- _ = self . abort_sender . send ( message) ;
379
- AbortWaiter { processed_receiver }
378
+ ///
379
+ /// Returns `Err(message)` if the engine has already completed execution.
380
+ pub fn abort (
381
+ & self ,
382
+ message : impl Into < String > ,
383
+ ) -> Result < AbortWaiter , String > {
384
+ let waiter = self . canceler . cancel ( message. into ( ) ) ?;
385
+ Ok ( AbortWaiter { waiter } )
380
386
}
381
387
}
382
388
@@ -386,7 +392,7 @@ impl AbortHandle {
386
392
/// Dropping this future does not cancel the abort.
387
393
#[ derive( Debug ) ]
388
394
pub struct AbortWaiter {
389
- processed_receiver : oneshot :: Receiver < ( ) > ,
395
+ waiter : coop_cancel :: Waiter < String > ,
390
396
}
391
397
392
398
impl Future for AbortWaiter {
@@ -396,24 +402,7 @@ impl Future for AbortWaiter {
396
402
mut self : Pin < & mut Self > ,
397
403
cx : & mut std:: task:: Context < ' _ > ,
398
404
) -> Poll < Self :: Output > {
399
- // The return value of the receiver doesn't matter. If it's an error, it
400
- // means that the sender was dropped, which means that execution
401
- // finished.
402
- _ = ready ! ( self . as_mut( ) . processed_receiver. poll_unpin( cx) ) ;
403
- Poll :: Ready ( ( ) )
404
- }
405
- }
406
-
407
- #[ derive( Debug ) ]
408
- struct AbortMessage {
409
- message : String ,
410
- processed_sender : oneshot:: Sender < ( ) > ,
411
- }
412
-
413
- impl AbortMessage {
414
- fn new ( message : String ) -> ( Self , oneshot:: Receiver < ( ) > ) {
415
- let ( processed_sender, processed_receiver) = oneshot:: channel ( ) ;
416
- ( Self { message, processed_sender } , processed_receiver)
405
+ self . waiter . poll_unpin ( cx)
417
406
}
418
407
}
419
408
@@ -786,7 +775,7 @@ impl<'a, S: StepSpec> StepExec<'a, S> {
786
775
self ,
787
776
log : & slog:: Logger ,
788
777
step_exec_cx : StepExecutionContext < S , F > ,
789
- abort_receiver : & mut mpsc :: UnboundedReceiver < AbortMessage > ,
778
+ cancel_receiver : & mut coop_cancel :: Receiver < String > ,
790
779
) -> Result <
791
780
( Result < StepOutcome < S > , S :: Error > , StepProgressReporter < S , F > ) ,
792
781
ExecutionError < S > ,
@@ -859,7 +848,7 @@ impl<'a, S: StepSpec> StepExec<'a, S> {
859
848
}
860
849
}
861
850
862
- Some ( message) = abort_receiver . recv( ) => {
851
+ Some ( message) = cancel_receiver . recv( ) => {
863
852
return Err ( reporter. handle_abort( message) . await ) ;
864
853
}
865
854
}
@@ -1080,7 +1069,7 @@ impl<S: StepSpec, F: Fn() -> usize> StepProgressReporter<S, F> {
1080
1069
}
1081
1070
}
1082
1071
1083
- async fn handle_abort ( self , message : AbortMessage ) -> ExecutionError < S > {
1072
+ async fn handle_abort ( self , message : String ) -> ExecutionError < S > {
1084
1073
// Send the abort message over the channel.
1085
1074
//
1086
1075
// The only way this can fail is if the event receiver is closed or
@@ -1098,21 +1087,17 @@ impl<S: StepSpec, F: Fn() -> usize> StepProgressReporter<S, F> {
1098
1087
attempt : self . attempt ,
1099
1088
step_elapsed : self . step_start . elapsed ( ) ,
1100
1089
attempt_elapsed : self . attempt_start . elapsed ( ) ,
1101
- message : message. message . clone ( ) ,
1090
+ message : message. clone ( ) ,
1102
1091
} ,
1103
1092
} ) )
1104
1093
. await ;
1105
1094
1106
- // An error here doesn't matter -- it just means that the abort handle
1107
- // was dropped.
1108
- _ = message. processed_sender . send ( ( ) ) ;
1109
-
1110
1095
match res {
1111
1096
Ok ( ( ) ) => ExecutionError :: Aborted {
1112
1097
component : self . step_info . info . component . clone ( ) ,
1113
1098
id : self . step_info . info . id . clone ( ) ,
1114
1099
description : self . step_info . info . description . clone ( ) ,
1115
- message : message. message ,
1100
+ message : message,
1116
1101
} ,
1117
1102
Err ( error) => error. into ( ) ,
1118
1103
}
0 commit comments