aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2020-05-20 14:51:53 +0100
committerChristopher Baines <mail@cbaines.net>2020-05-20 17:29:49 +0100
commit93e21eb79cecede9e5d8da220db90bd132dd2f7d (patch)
treed4e305f5955b077017b65678e6bf04ad83f28118
parentf9993a86375e5f0de64827d43728f99cda4faa87 (diff)
downloadbuild-coordinator-93e21eb79cecede9e5d8da220db90bd132dd2f7d.tar
build-coordinator-93e21eb79cecede9e5d8da220db90bd132dd2f7d.tar.gz
Try to better handle/avoid http related failures
I'm seeing "Resource temporarily unavailable, try again" errors from GnuTLS, mostly around the file uploads I think. I'm not sure what's going on here, but it seems to happen when using multiple threads in parallel. Anyway, this commit uses some mutexes to avoid uploading files in parallel, and also improves error handling generally. I'm pretty sure this isn't sufficient to fix the issue, but I could be looking in completely the wrong place for the problem.
-rw-r--r--guix-build-coordinator/agent-messaging/http.scm169
1 files changed, 102 insertions, 67 deletions
diff --git a/guix-build-coordinator/agent-messaging/http.scm b/guix-build-coordinator/agent-messaging/http.scm
index 117745a..5ad0a4b 100644
--- a/guix-build-coordinator/agent-messaging/http.scm
+++ b/guix-build-coordinator/agent-messaging/http.scm
@@ -23,6 +23,7 @@
#:use-module (srfi srfi-19)
#:use-module (ice-9 match)
#:use-module (ice-9 format)
+ #:use-module (ice-9 threads)
#:use-module (ice-9 exceptions)
#:use-module (ice-9 textual-ports)
#:use-module (ice-9 binary-ports)
@@ -445,6 +446,29 @@ port. Also, the port used can be changed by passing the --port option.\n"
agent-path
(string-drop agent-path 1))))))
+(define (with-request-mutex thunk)
+ (monitor (thunk)))
+
+(define* (coordinator-handle-failed-request method path response body
+ #:key first-request-failed?)
+ (simple-format
+ (current-error-port)
+ "error: coordinator-http-request: ~A ~A: ~A\n"
+ method path (response-code response))
+
+ (catch #t
+ (lambda ()
+ (if (equal? '(application/json (charset . "utf-8"))
+ (response-content-type response))
+ (json-string->scm (utf8->string body))
+ (utf8->string body)))
+ (lambda (key . args)
+ (simple-format
+ (current-error-port)
+ "error decoding body ~A ~A\n"
+ key args)
+ #f)))
+
(define* (coordinator-http-request coordinator-uri agent-uuid password
path
#:key method body (headers '())
@@ -464,46 +488,35 @@ port. Also, the port used can be changed by passing the --port option.\n"
(define (make-request)
(let-values (((response body)
- (http-request uri
- #:method method
- #:body (scm->json-string body)
- #:decode-body? #f
- #:headers
- `((Authorization . ,auth-value)
- ,@headers))))
+ (with-request-mutex
+ (lambda ()
+ (http-request uri
+ #:method method
+ #:body (scm->json-string body)
+ #:decode-body? #f
+ #:headers
+ `((Authorization . ,auth-value)
+ ,@headers))))))
(if (>= (response-code response) 400)
- (begin
- (simple-format
- (current-error-port)
- "error: coordinator-http-request: ~A ~A: ~A\n"
- method path (response-code response))
- (let ((body
- (catch #t
- (lambda ()
- (if (equal? '(application/json (charset . "utf-8"))
- (response-content-type response))
- (json-string->scm (utf8->string body))
- (utf8->string body)))
- (lambda (key . args)
- (simple-format
- (current-error-port)
- "error decoding body ~A ~A\n"
- key args)
- #f))))
- (if (and first-request-failed?
- succeed-on-access-denied-retry?
- (equal? body
- '(("error" . "access denied"))))
- (begin
- (simple-format
- (current-error-port)
- "warning: treating access denied response as success\n")
- (values body response))
- (begin
- (set! first-request-failed? #t)
- (raise-exception
- (make-exception-with-message
- body))))))
+ (let ((body
+ (coordinator-handle-failed-request method
+ path
+ response
+ body)))
+ (if (and first-request-failed?
+ succeed-on-access-denied-retry?
+ (equal? body
+ '(("error" . "access denied"))))
+ (begin
+ (simple-format
+ (current-error-port)
+ "warning: treating access denied response as success\n")
+ (values body response))
+ (begin
+ (set! first-request-failed? #t)
+ (raise-exception
+ (make-exception-with-message
+ body)))))
(values
(json-string->scm (utf8->string body))
response))))
@@ -545,14 +558,16 @@ port. Also, the port used can be changed by passing the --port option.\n"
5000000) ; 5MB
(retry-on-error
(lambda ()
- (call-with-streaming-http-request
- uri
- (lambda (port)
- (call-with-lzip-output-port port
- (lambda (port)
- (write-file file port))
- #:level 9))
- #:headers `((Authorization . ,auth-value))))
+ (with-request-mutex
+ (lambda ()
+ (call-with-streaming-http-request
+ uri
+ (lambda (port)
+ (call-with-lzip-output-port port
+ (lambda (port)
+ (write-file file port))
+ #:level 9))
+ #:headers `((Authorization . ,auth-value))))))
#:times 3
#:delay 30)
(let* ((directory (or (getenv "TMPDIR") "/tmp"))
@@ -570,18 +585,28 @@ port. Also, the port used can be changed by passing the --port option.\n"
(simple-format #t "finished compressing ~A, now sending\n" file)
(retry-on-error
(lambda ()
- (call-with-input-file template
- (lambda (file-port)
- (call-with-streaming-http-request
- uri
- (lambda (port)
- (with-time-logging
- (simple-format #f "sending ~A" file)
- (dump-port file-port port
- #:buffer-size (expt 2 20))))
- #:headers `((Authorization . ,auth-value))))))
+ (with-request-mutex
+ (lambda ()
+ (call-with-input-file template
+ (lambda (file-port)
+ (let-values (((response body)
+ (call-with-streaming-http-request
+ uri
+ (lambda (port)
+ (with-time-logging
+ (simple-format #f "sending ~A" file)
+ (dump-port file-port port
+ #:buffer-size (expt 2 20))))
+ #:headers `((Authorization . ,auth-value)))))
+ (when (>= (response-code response) 400)
+ (raise-exception
+ (make-exception-with-message
+ (coordinator-handle-failed-request 'PUT
+ (uri-path uri)
+ response
+ body))))))))))
#:times 9
- #:delay 30)
+ #:delay (+ 60 (random 120)))
(delete-file template))))
@@ -608,16 +633,26 @@ port. Also, the port used can be changed by passing the --port option.\n"
(retry-on-error
(lambda ()
- (call-with-streaming-http-request
- uri
- (lambda (request-port)
- (call-with-input-file file
- (lambda (file-port)
- (dump-port file-port request-port))
- #:binary #t))
- #:headers `((Authorization . ,auth-value))))
+ (with-request-mutex
+ (lambda ()
+ (let-values (((response body)
+ (call-with-streaming-http-request
+ uri
+ (lambda (request-port)
+ (call-with-input-file file
+ (lambda (file-port)
+ (dump-port file-port request-port))
+ #:binary #t))
+ #:headers `((Authorization . ,auth-value)))))
+ (when (>= (response-code response) 400)
+ (raise-exception
+ (make-exception-with-message
+ (coordinator-handle-failed-request 'PUT
+ (uri-path uri)
+ response
+ body))))))))
#:times 9
- #:delay 30))
+ #:delay (+ 30 (random 60))))
(define (submit-build-result coordinator-uri agent-uuid password
build-id result)