1- use sqlx:: PgPool ;
1+ use sqlx:: { PgPool , Postgres , Transaction } ;
22use uuid:: Uuid ;
33
44use crate :: {
@@ -365,17 +365,18 @@ pub async fn cancel(pool: &PgPool, id: Uuid) -> Result<Option<Evaluation>> {
365365 )
366366}
367367
368- /// Requeue a cancelled or failed evaluation after discarding its stale builds.
368+ /// Requeue a cancelled, failed, or timed-out evaluation after discarding its
369+ /// stale builds. One-shot jobsets are re-enabled for the new attempt.
369370///
370371/// # Errors
371372///
372373/// Returns an error if the database transaction fails.
373374pub async fn restart ( pool : & PgPool , id : Uuid ) -> Result < Option < Evaluation > > {
374375 let mut tx = pool. begin ( ) . await ?;
375376 let evaluation = sqlx:: query_as :: < _ , Evaluation > (
376- "UPDATE evaluations SET status = 'pending', error_message = NULL , \
377- inputs_hash = NULL WHERE id = $1 AND status IN ('cancelled', 'failed') \
378- RETURNING *",
377+ "UPDATE evaluations SET status = 'pending', evaluation_time = NOW() , \
378+ error_message = NULL, inputs_hash = NULL WHERE id = $1 AND status IN \
379+ ('cancelled', 'failed', 'timed_out') RETURNING *",
379380 )
380381 . bind ( id)
381382 . fetch_optional ( & mut * tx)
@@ -386,11 +387,64 @@ pub async fn restart(pool: &PgPool, id: Uuid) -> Result<Option<Evaluation>> {
386387 . bind ( id)
387388 . execute ( & mut * tx)
388389 . await ?;
390+ sqlx:: query (
391+ "UPDATE jobsets SET enabled = true WHERE id = (SELECT jobset_id FROM \
392+ evaluations WHERE id = $1) AND state = 'one_shot'",
393+ )
394+ . bind ( id)
395+ . execute ( & mut * tx)
396+ . await ?;
389397 }
390398 tx. commit ( ) . await ?;
391399 Ok ( evaluation)
392400}
393401
402+ /// Lock a running evaluation before atomically persisting its result.
403+ ///
404+ /// # Errors
405+ ///
406+ /// Returns an error if the database query fails.
407+ pub async fn lock_running (
408+ tx : & mut Transaction < ' _ , Postgres > ,
409+ id : Uuid ,
410+ ) -> Result < bool > {
411+ Ok (
412+ sqlx:: query_scalar :: < _ , Uuid > (
413+ "SELECT id FROM evaluations WHERE id = $1 AND status = 'running' FOR \
414+ UPDATE",
415+ )
416+ . bind ( id)
417+ . fetch_optional ( & mut * * tx)
418+ . await ?
419+ . is_some ( ) ,
420+ )
421+ }
422+
423+ /// Finish a locked running evaluation within its result transaction.
424+ ///
425+ /// # Errors
426+ ///
427+ /// Returns an error if the database query fails.
428+ pub async fn finish_running_in_transaction (
429+ tx : & mut Transaction < ' _ , Postgres > ,
430+ id : Uuid ,
431+ status : EvaluationStatus ,
432+ error_message : Option < & str > ,
433+ ) -> Result < bool > {
434+ Ok (
435+ sqlx:: query_scalar :: < _ , Uuid > (
436+ "UPDATE evaluations SET status = $1, error_message = $2 WHERE id = $3 \
437+ AND status = 'running' RETURNING id",
438+ )
439+ . bind ( status)
440+ . bind ( error_message)
441+ . bind ( id)
442+ . fetch_optional ( & mut * * tx)
443+ . await ?
444+ . is_some ( ) ,
445+ )
446+ }
447+
394448/// Return whether an evaluator should cancel its currently-running work.
395449///
396450/// # Errors
0 commit comments