Parcourir la source

Create and destroy a tiny image during health check to check that vips is operational

DarthSim il y a 1 an
Parent
commit
925dac28bb
5 fichiers modifiés avec 68 ajouts et 3 suppressions
  1. 1 0
      CHANGELOG.md
  2. 20 3
      server.go
  3. 14 0
      vips/vips.c
  4. 31 0
      vips/vips.go
  5. 2 0
      vips/vips.h

+ 1 - 0
CHANGELOG.md

@@ -9,6 +9,7 @@
 
 ### Change
 - Don't report `The image request is cancelled` errors.
+- Create and destroy a tiny image during health check to check that vips is operational.
 - (pro) Change the `/info` endpoint behavior to return only the first EXIF/XMP/IPTC block data of JPEG if the image contains multiple metadata blocks of the same type.
 
 ### Fix

+ 20 - 3
server.go

@@ -17,6 +17,7 @@ import (
 	"github.com/imgproxy/imgproxy/v3/metrics"
 	"github.com/imgproxy/imgproxy/v3/reuseport"
 	"github.com/imgproxy/imgproxy/v3/router"
+	"github.com/imgproxy/imgproxy/v3/vips"
 )
 
 var (
@@ -165,10 +166,26 @@ func withPanicHandler(h router.RouteHandler) router.RouteHandler {
 }
 
 func handleHealth(reqID string, rw http.ResponseWriter, r *http.Request) {
-	router.LogResponse(reqID, r, 200, nil)
+	var (
+		status int
+		msg    []byte
+		ierr   *ierrors.Error
+	)
+
+	if err := vips.Health(); err == nil {
+		status = http.StatusOK
+		msg = imgproxyIsRunningMsg
+	} else {
+		status = http.StatusInternalServerError
+		msg = []byte("Error")
+		ierr = ierrors.Wrap(err, 1)
+	}
+
+	router.LogResponse(reqID, r, status, ierr)
+
 	rw.Header().Set("Cache-Control", "no-cache")
-	rw.WriteHeader(200)
-	rw.Write(imgproxyIsRunningMsg)
+	rw.WriteHeader(status)
+	rw.Write(msg)
 }
 
 func handleHead(reqID string, rw http.ResponseWriter, r *http.Request) {

+ 14 - 0
vips/vips.c

@@ -50,6 +50,20 @@ gif_resolution_limit() {
 #endif
 }
 
+// Just create and destroy a tiny image to ensure vips is operational
+int
+vips_health() {
+  VipsImage *base = vips_image_new();
+  VipsImage **t = (VipsImage **) vips_object_local_array(VIPS_OBJECT(base), 2);
+
+  int res = vips_black(&t[0], 4, 4, "bands", 4, NULL) ||
+    !(t[1] = vips_image_copy_memory(t[0]));
+
+  clear_image(&base);
+
+  return res;
+}
+
 int
 vips_jpegload_go(void *buf, size_t len, int shrink, VipsImage **out) {
   if (shrink > 1)

+ 31 - 0
vips/vips.go

@@ -7,12 +7,14 @@ package vips
 */
 import "C"
 import (
+	"context"
 	"errors"
 	"math"
 	"os"
 	"runtime"
 	"strings"
 	"sync"
+	"time"
 	"unsafe"
 
 	log "github.com/sirupsen/logrus"
@@ -147,6 +149,35 @@ func GetAllocs() float64 {
 	return float64(C.vips_tracked_get_allocs())
 }
 
+func Health() error {
+	timer := time.NewTimer(5 * time.Second)
+	defer timer.Stop()
+
+	done := make(chan struct{})
+
+	var err error
+
+	go func(done chan struct{}) {
+		runtime.LockOSThread()
+		defer runtime.UnlockOSThread()
+
+		defer Cleanup()
+
+		if C.vips_health() != 0 {
+			err = Error()
+		}
+
+		close(done)
+	}(done)
+
+	select {
+	case <-done:
+		return err
+	case <-timer.C:
+		return context.DeadlineExceeded
+	}
+}
+
 func Cleanup() {
 	C.vips_cleanup()
 }

+ 2 - 0
vips/vips.h

@@ -13,6 +13,8 @@ void swap_and_clear(VipsImage **in, VipsImage *out);
 
 int gif_resolution_limit();
 
+int vips_health();
+
 int vips_jpegload_go(void *buf, size_t len, int shrink, VipsImage **out);
 int vips_pngload_go(void *buf, size_t len, VipsImage **out);
 int vips_webpload_go(void *buf, size_t len, double scale, int pages, VipsImage **out);