@@ -9,6 +9,7 @@ use std::ffi::{OsStr, OsString};
99use std:: time:: { Duration , Instant } ;
1010use subprocess:: { Exec , Redirection , ExitStatus , CaptureData , PopenConfig } ;
1111use ureq:: { Agent , AgentBuilder , Error , Response } ;
12+ use uuid:: Uuid ;
1213
1314static MAX_BYTES_TO_POST : usize = 10000 ; // not 10KB, https://healthchecks.io/docs/attaching_logs/
1415static MAX_STRING_TO_LOG : usize = 1000 ;
@@ -96,18 +97,25 @@ impl HCAgent {
9697 HCAgent { agent, verbose : cli. verbose , url_prefix : cli. url_prefix ( ) }
9798 }
9899
99- /// Pings the Healthchecks server to notify that the task denoted by the UUID is starting
100- fn notify_start ( & self ) -> Result < Response , Error > {
101- let req = self . agent . get ( & format ! ( "{}/start" , self . url_prefix) ) ;
100+ /// Pings the Healthchecks server to notify that the task denoted by the URL prefix is starting
101+ /// A run_id UUID is used to associate this event with its completion notification
102+ fn notify_start ( & self , run_id : Uuid ) -> Result < Response , Error > {
103+ let url = format ! ( "{}/start?rid={}" , self . url_prefix, run_id) ;
104+ let req = self . agent . get ( & url) ;
102105 if self . verbose { eprintln ! ( "Sending request: {:?}" , req) ; }
103106 req. call ( )
104107 }
105108
106109 /// Pings the Healthchecks server to notify that the task denoted by the URL prefix is done.
110+ /// A run_id UUID is used to associated this event with its start notification, if one was sent
107111 /// If code is non-zero, the task will be considered failed. If code is None the task will be logged
108112 /// but not update the check.
109- fn notify_complete ( & self , code : Option < u8 > , output : & str ) -> Result < Response , Error > {
110- let req = self . agent . post ( & format ! ( "{}/{}" , self . url_prefix, code. map( |x| x. to_string( ) ) . unwrap_or_else( || "log" . to_string( ) ) ) ) ;
113+ fn notify_complete ( & self , run_id : Option < Uuid > , code : Option < u8 > , output : & str ) -> Result < Response , Error > {
114+ let mut url = format ! ( "{}/{}" , self . url_prefix, code. map( |x| x. to_string( ) ) . unwrap_or_else( || "log" . to_string( ) ) ) ;
115+ if let Some ( run_id) = run_id {
116+ url = format ! ( "{}?rid={}" , url, run_id) ;
117+ }
118+ let req = self . agent . post ( & url) ;
111119 if self . verbose { eprintln ! ( "Sending request: {:?}" , req) ; }
112120 if output. is_empty ( ) {
113121 req. call ( )
@@ -192,8 +200,11 @@ impl Cli {
192200}
193201
194202fn run ( cli : Cli , agent : HCAgent ) -> Result < Response , Error > {
203+ let mut maybe_run_id = None ; // Don't bother reporting a run ID unless we're sending a start ping
195204 if cli. time {
196- if let Err ( e) = agent. notify_start ( ) {
205+ let run_id = Uuid :: new_v4 ( ) ;
206+ maybe_run_id = Some ( run_id) ;
207+ if let Err ( e) = agent. notify_start ( run_id) {
197208 eprintln ! ( "Failed to send start request: {:?}" , e) ;
198209 }
199210 }
@@ -220,7 +231,7 @@ fn run(cli: Cli, agent: HCAgent) -> Result<Response, Error> {
220231 // Trim replacement chars added by from_utf8_lossy since they are multi-byte and can actually
221232 // increase the length of the string.
222233 let code = if cli. log { None } else { Some ( code) } ;
223- agent. notify_complete ( code, output. trim_start_matches ( |c| c=='�' ) )
234+ agent. notify_complete ( maybe_run_id , code, output. trim_start_matches ( |c| c=='�' ) )
224235}
225236
226237fn main ( ) {
@@ -276,16 +287,23 @@ mod tests {
276287 let suc_m = mockito:: mock ( "POST" , "/ping/0" ) . match_body ( "foo bar" ) . with_status ( 200 ) . create ( ) ;
277288 let fail_m = mockito:: mock ( "POST" , "/ping/10" ) . match_body ( "bar baz" ) . with_status ( 200 ) . create ( ) ;
278289 let log_m = mockito:: mock ( "POST" , "/ping/log" ) . match_body ( "bang boom" ) . with_status ( 200 ) . create ( ) ;
290+ let runid_m = mockito:: mock ( "POST" , "/ping/0" )
291+ . match_query ( mockito:: Matcher :: Regex ( "rid=.*" . into ( ) ) )
292+ . match_body ( "run id" )
293+ . with_status ( 200 ) . create ( ) ;
279294 let agent = HCAgent { agent : Agent :: new ( ) , verbose : false , url_prefix : format ! ( "{}/{}" , mockito:: server_url( ) , "ping" ) } ;
280- let suc_response = agent. notify_complete ( Some ( 0 ) , "foo bar" ) ;
281- let fail_response = agent. notify_complete ( Some ( 10 ) , "bar baz" ) ;
282- let log_response = agent. notify_complete ( None , "bang boom" ) ;
295+ let suc_response = agent. notify_complete ( None , Some ( 0 ) , "foo bar" ) ;
296+ let fail_response = agent. notify_complete ( None , Some ( 10 ) , "bar baz" ) ;
297+ let log_response = agent. notify_complete ( None , None , "bang boom" ) ;
298+ let runid_response = agent. notify_complete ( Some ( Uuid :: from_u128 ( 1234 ) ) , Some ( 0 ) , "run id" ) ;
283299 suc_m. assert ( ) ;
284300 fail_m. assert ( ) ;
285301 log_m. assert ( ) ;
302+ runid_m. assert ( ) ;
286303 suc_response. unwrap ( ) ;
287304 fail_response. unwrap ( ) ;
288305 log_response. unwrap ( ) ;
306+ runid_response. unwrap ( ) ;
289307 }
290308
291309 mod integ {
@@ -335,11 +353,13 @@ mod tests {
335353
336354 #[ test]
337355 fn start ( ) {
338- let m = mockito:: mock ( "GET" , "/start/start" ) . with_status ( 200 ) . create ( ) ;
356+ let m = mockito:: mock ( "GET" , "/start/start" )
357+ . match_query ( mockito:: Matcher :: Regex ( "rid=.*" . into ( ) ) )
358+ . with_status ( 200 ) . create ( ) ;
339359
340360 let cli = fake_cli ( "start" , & [ "" ] ) ;
341361
342- let response = HCAgent :: create ( & cli) . notify_start ( ) ;
362+ let response = HCAgent :: create ( & cli) . notify_start ( Uuid :: from_u128 ( 1234 ) ) ;
343363 m. assert ( ) ;
344364 response. unwrap ( ) ;
345365 }
@@ -388,9 +408,13 @@ mod tests {
388408
389409 #[ test]
390410 fn timed ( ) {
391- let start_m = mockito:: mock ( "GET" , "/timed/start" ) . with_status ( 200 ) . create ( ) ;
411+ let start_m = mockito:: mock ( "GET" , "/timed/start" )
412+ . match_query ( mockito:: Matcher :: Regex ( "rid=.*" . into ( ) ) )
413+ . with_status ( 200 ) . create ( ) ;
392414 let done_m = mockito:: mock ( "POST" , "/timed/0" )
393- . match_body ( "hello\n " ) . with_status ( 200 ) . create ( ) ;
415+ . match_query ( mockito:: Matcher :: Regex ( "rid=.*" . into ( ) ) )
416+ . match_body ( "hello\n " )
417+ . with_status ( 200 ) . create ( ) ;
394418
395419 let mut cli = fake_cli ( "timed" , & [ "echo" , "hello" ] ) ;
396420 cli. time = true ;
0 commit comments