branch: main
commit f9797893145dd6ca7712efb7af6180a1f8e35c87
Author: Ludovic Courtès <l...@gnu.org>
AuthorDate: Tue Apr 1 11:42:08 2025 +0200

    base: Fail-safe if an evaluation’s spec was removed.
    
    Evaluations might start or complete after their corresponding
    specification has been removed.  Swallow “foreign key constraint
    violations” errors that occur in such situations.
    
    * src/cuirass/database.scm (db-add-evaluation/fail-safe)
    (db-set-evaluation-status/fail-safe): New procedures.
    * src/cuirass/base.scm (evaluate, start-evaluation)
    (jobset-evaluator): Use them.
---
 src/cuirass/base.scm     | 15 ++++++++-------
 src/cuirass/database.scm | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/src/cuirass/base.scm b/src/cuirass/base.scm
index cc17ead..479b976 100644
--- a/src/cuirass/base.scm
+++ b/src/cuirass/base.scm
@@ -684,8 +684,8 @@ Return a list of jobs that are associated to EVAL-ID."
                    ;; otherwise, suppose that data read from port are
                    ;; correct and keep things going.
                    ((? eof-object?)
-                    (db-set-evaluation-status eval-id
-                                              (evaluation-status failed))
+                    (db-set-evaluation-status/fail-safe eval-id spec
+                                                        (evaluation-status 
failed))
                     #f)
                    (_ #t))))
     (close-port (cdr log-pipe))
@@ -715,9 +715,10 @@ evaluation ID before the evaluation is started."
                     ;; Include possible channel dependencies
                     (channels channels)))
          (checkouttime (time-second (current-time time-utc)))
-         (eval-id (db-add-evaluation (specification-name spec) instances
-                                     #:timestamp timestamp
-                                     #:checkouttime checkouttime)))
+         (eval-id (db-add-evaluation/fail-safe (specification-name spec)
+                                               instances
+                                               #:timestamp timestamp
+                                               #:checkouttime checkouttime)))
 
     (and eval-id
          (guard (c ((evaluation-error? c)
@@ -771,8 +772,8 @@ evaluation ID before the evaluation is started."
                      (derivations (map build-derivation builds)))
                 (log-info "evaluation ~a of jobset '~a' registered ~a builds"
                           eval-id (specification-name spec) (length builds))
-                (db-set-evaluation-status eval-id
-                                          (evaluation-status succeeded))
+                (db-set-evaluation-status/fail-safe eval-id spec
+                                                    (evaluation-status 
succeeded))
 
                 ;; Register a GC root for each derivation so that they are not
                 ;; garbage collected before getting built.
diff --git a/src/cuirass/database.scm b/src/cuirass/database.scm
index 6e0923d..fd366c7 100644
--- a/src/cuirass/database.scm
+++ b/src/cuirass/database.scm
@@ -154,9 +154,11 @@
             db-get-specifications
             evaluation-status
             db-add-evaluation
+            db-add-evaluation/fail-safe
             db-abort-pending-evaluations
             db-remove-old-evaluations
             db-set-evaluation-status
+            db-set-evaluation-status/fail-safe
             db-set-evaluation-time
             build-status
             build-weather
@@ -709,6 +711,25 @@ RETURNING id;"))
             (rollback #f)
             eval-id)))))
 
+(define* (db-add-evaluation/fail-safe spec-name instances
+                                      #:key
+                                      (checkouttime 0)
+                                      (evaltime 0)
+                                      timestamp)
+  "Like 'db-add-evaluation', but catch errors that might occur for
+example of SPEC was deleted from the database in the meantime.  Return the
+evaluation ID if it was inserted and #f otherwise."
+  (catch 'psql-query-error
+    (lambda ()
+      (db-add-evaluation spec-name instances
+                         #:checkouttime checkouttime
+                         #:evaltime evaltime
+                         #:timestamp timestamp))
+    (lambda (key . args)
+      (log-error "failed to add evaluation for jobset '~a': ~s"
+                 spec-name args)
+      #f)))
+
 (define (db-abort-pending-evaluations)
   (with-db-connection db
     (exec-query/bind db "UPDATE Evaluations SET status =
@@ -720,6 +741,18 @@ RETURNING id;"))
     (exec-query/bind db "UPDATE Evaluations SET status =
 " status " WHERE id = " eval-id ";")))
 
+(define (db-set-evaluation-status/fail-safe eval-id spec status)
+  "Like 'db-set-evaluation-status', but catch errors that might occur for
+example of SPEC was deleted from the database in the meantime."
+  (catch 'psql-query-error
+    (lambda ()
+      (db-set-evaluation-status eval-id status))
+    (lambda (key . args)
+      (log-error "failed to update evaluation ~a of \
+jobset '~a': ~s"
+                 eval-id (specification-name spec))
+      #f)))
+
 (define (db-set-evaluation-time eval-id)
   (define now
     (time-second (current-time time-utc)))

Reply via email to