diff options
author | Christopher Baines <mail@cbaines.net> | 2025-01-06 11:46:32 +0000 |
---|---|---|
committer | Christopher Baines <mail@cbaines.net> | 2025-01-06 11:46:32 +0000 |
commit | 1a31302d2332bd5f70115e19ac32e0a013b1ea62 (patch) | |
tree | 8becdd8ccccc28b2bdebc7be810f5c6750c53aec /guix-qa-frontpage/mumi.scm | |
parent | 572be25bcf29e5e4d0977bbdd661006bfbadd2cc (diff) | |
download | qa-frontpage-1a31302d2332bd5f70115e19ac32e0a013b1ea62.tar qa-frontpage-1a31302d2332bd5f70115e19ac32e0a013b1ea62.tar.gz |
Cache connections when talking to mumi
Diffstat (limited to 'guix-qa-frontpage/mumi.scm')
-rw-r--r-- | guix-qa-frontpage/mumi.scm | 165 |
1 files changed, 117 insertions, 48 deletions
diff --git a/guix-qa-frontpage/mumi.scm b/guix-qa-frontpage/mumi.scm index 94c1842..80f3646 100644 --- a/guix-qa-frontpage/mumi.scm +++ b/guix-qa-frontpage/mumi.scm @@ -18,6 +18,7 @@ (define-module (guix-qa-frontpage mumi) #:use-module (srfi srfi-1) + #:use-module (srfi srfi-71) #:use-module (ice-9 match) #:use-module (json) #:use-module (kolam http) @@ -33,6 +34,75 @@ mumi-bulk-issues)) +(define (at-most max-length lst) + "If LST is shorter than MAX-LENGTH, return it and the empty list; otherwise +return its MAX-LENGTH first elements and its tail." + (let loop ((len 0) + (lst lst) + (result '())) + (match lst + (() + (values (reverse result) '())) + ((head . tail) + (if (>= len max-length) + (values (reverse result) lst) + (loop (+ 1 len) tail (cons head result))))))) + +(define %max-cached-connections + ;; Maximum number of connections kept in cache by + ;; 'open-connection-for-uri/cached'. + 16) + +(define open-socket-for-uri/cached + (let ((cache '())) + (lambda* (uri #:key fresh? verify-certificate?) + "Return a connection for URI, possibly reusing a cached connection. +When FRESH? is true, delete any cached connections for URI and open a new one. +Return #f if URI's scheme is 'file' or #f. + +When VERIFY-CERTIFICATE? is true, verify HTTPS server certificates." + (define host (uri-host uri)) + (define scheme (uri-scheme uri)) + (define key (list host scheme (uri-port uri))) + + (and (not (memq scheme '(file #f))) + (match (assoc-ref cache key) + (#f + ;; Open a new connection to URI and evict old entries from + ;; CACHE, if any. + (let ((socket + (open-socket-for-uri + uri + #:verify-certificate? verify-certificate?)) + (new-cache evicted + (at-most (- %max-cached-connections 1) cache))) + (for-each (match-lambda + ((_ . port) + (false-if-exception (close-port port)))) + evicted) + (set! cache (alist-cons key socket new-cache)) + socket)) + (socket + (if (or fresh? (port-closed? socket)) + (begin + (false-if-exception (close-port socket)) + (set! cache (alist-delete key cache)) + (open-socket-for-uri/cached uri + #:verify-certificate? + verify-certificate?)) + (begin + ;; Drain input left from the previous use. + (drain-input socket) + socket)))))))) + +(define (call-with-cached-connection uri proc) + (let ((port (open-socket-for-uri/cached uri))) + (with-throw-handler #t + (lambda () + (proc port)) + (lambda _ + (close-port port))))) + (define* (graphql-http-get* uri document #:key (verify-certificate? #t) @@ -43,22 +113,25 @@ (variables '())) (call-with-values (lambda () - (http-get - (string-append uri - "?query=" - (uri-encode (scm->graphql-string document)) - "&" - "variables=" - (uri-encode (scm->json-string - ((@@ (kolam http) variables->alist) - variables)))) - #:streaming? #t - #:keep-alive? keep-alive? - #:verify-certificate? verify-certificate? - #:port port)) + (let ((response + body + (http-get + (string-append uri + "?query=" + (uri-encode (scm->graphql-string document)) + "&" + "variables=" + (uri-encode (scm->json-string + ((@@ (kolam http) variables->alist) + variables)))) + #:streaming? #t + #:keep-alive? keep-alive? + #:verify-certificate? verify-certificate? + #:port port))) + (values response + body))) (@@ (kolam http) graphql-http-response))) - (define (mumi-search-issues query) (let ((response (graphql-http-get "https://issues.guix.gnu.org/graphql" @@ -80,17 +153,14 @@ (let ((number-to-data (make-hash-table))) - (let loop ((chunks (chunk! (list-copy numbers) - 30)) - (port - (open-socket-for-uri - (string->uri url) - #:verify-certificate? #t))) - (if (null? chunks) - (close-port port) - (let ((response - (retry-on-error - (lambda () + (for-each + (lambda (chunk) + (let ((response + (retry-on-error + (lambda () + (call-with-cached-connection + (string->uri url) + (lambda (port) (graphql-http-get* url `(document @@ -98,30 +168,29 @@ `(query (#(issue #:number ,number) number title open severity tags (merged_with number)))) - (car chunks))) + chunk)) #:keep-alive? #t - #:port port)) - #:times 1 - #:delay 0))) - - (for-each - (lambda (res) - (let ((data (cdr res))) - (hash-set! number-to-data - (assoc-ref data "number") - `((title . ,(assoc-ref data "title")) - (open? . ,(assoc-ref data "open")) - (tags . ,(vector->list - (assoc-ref data "tags"))) - (merged-with . ,(map - (lambda (data) - (assoc-ref data "number")) - (vector->list - (assoc-ref data "merged_with")))) - (severity . ,(assoc-ref data "severity")))))) - response) - - (loop (cdr chunks) port)))) + #:port port)))) + #:times 1 + #:delay 0))) + + (for-each + (lambda (res) + (let ((data (cdr res))) + (hash-set! number-to-data + (assoc-ref data "number") + `((title . ,(assoc-ref data "title")) + (open? . ,(assoc-ref data "open")) + (tags . ,(vector->list + (assoc-ref data "tags"))) + (merged-with . ,(map + (lambda (data) + (assoc-ref data "number")) + (vector->list + (assoc-ref data "merged_with")))) + (severity . ,(assoc-ref data "severity")))))) + response))) + (chunk! (list-copy numbers) 30)) (map (lambda (number) (hash-ref number-to-data number)) |