aboutsummaryrefslogtreecommitdiff
path: root/guix-data-service/web/server.scm
blob: 84a0e6b707179a36548c6a34523f749cbd604a69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
;;; Guix Data Service -- Information about Guix over time
;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net>
;;; Copyright © 2019, 2020, 2022, 2023 Christopher Baines <mail@cbaines.net>
;;;
;;; This program is free software: you can redistribute it and/or
;;; modify it under the terms of the GNU Affero General Public License
;;; as published by the Free Software Foundation, either version 3 of
;;; the License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; Affero General Public License for more details.
;;;
;;; You should have received a copy of the GNU Affero General Public
;;; License along with this program.  If not, see
;;; <http://www.gnu.org/licenses/>.

(define-module (guix-data-service web server)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-11)
  #:use-module (ice-9 match)
  #:use-module (web http)
  #:use-module (web request)
  #:use-module (web uri)
  #:use-module (system repl error-handling)
  #:use-module (ice-9 atomic)
  #:use-module (fibers)
  #:use-module (fibers conditions)
  #:use-module (prometheus)
  #:use-module (guix-data-service utils)
  #:use-module (guix-data-service database)
  #:use-module (guix-data-service web controller)
  #:use-module (guix-data-service web util)
  #:export (start-guix-data-service-web-server))

(define (check-startup-completed startup-completed)
  (if (atomic-box-ref startup-completed)
      (begin
        ;; Just in case this atomic-box-ref is expensive, only do it when
        ;; necessary
        (set! check-startup-completed (const #t))
        #t)
      #f))

(define (handler request body controller secret-key-base startup-completed
                 render-metrics)
  (display
   (format #f "~a ~a\n"
           (request-method request)
           (uri-path (request-uri request))))
  (apply values
         (let-values (((request-components mime-types)
                       (request->path-components-and-mime-type request)))
           (controller request
                       (cons (request-method request)
                             request-components)
                       mime-types
                       body
                       secret-key-base
                       (check-startup-completed startup-completed)
                       render-metrics))))

(define* (start-guix-data-service-web-server port host secret-key-base
                                             startup-completed
                                             #:key postgresql-statement-timeout
                                             postgresql-connections)
  (define registry
    (make-metrics-registry #:namespace "guixdataservice"))

  (define render-metrics
    (make-render-metrics registry))

  (%database-metrics-registry registry)

  (let ((finished? (make-condition)))
    (call-with-sigint
     (lambda ()
       (run-fibers
        (lambda ()
          (parameterize
              ((connection-pool
                (make-resource-pool
                 (lambda ()
                   (open-postgresql-connection
                    "web"
                    postgresql-statement-timeout))
                 (floor (/ postgresql-connections 2))))

               (reserved-connection-pool
                (make-resource-pool
                 (lambda ()
                   (open-postgresql-connection
                    "web-reserved"
                    postgresql-statement-timeout))
                 (floor (/ postgresql-connections 2))))

               (resource-pool-default-timeout 10))

            (with-exception-handler
                (lambda (exn)
                  (simple-format
                   (current-error-port)
                   "\n
error: guix-data-service could not start: ~A

Check if it's already running, or whether another process is using that
port. Also, the port used can be changed by passing the --port option.\n"
                   exn)
                  (primitive-exit 1))
              (lambda ()
                (run-server/patched
                 (lambda (request body)
                   (handler request body controller
                            secret-key-base
                            startup-completed
                            render-metrics))
                 #:host host
                 #:port port))
              #:unwind? #t))
          (wait finished?))))
     finished?)))