Skip to content

Commit d8cbae8

Browse files
committed
WIP: in-process version of Go template
The watchdog is imported as an SDK to avoid an extra hop and to reduce total memory usage of one Go process vs two. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
1 parent 2e6e262 commit d8cbae8

File tree

11 files changed

+300
-6
lines changed

11 files changed

+300
-6
lines changed

template/golang-http/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
FROM --platform=${TARGETPLATFORM:-linux/amd64} ghcr.io/openfaas/of-watchdog:0.10.11 AS watchdog
2-
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.24.0-alpine AS build
1+
FROM --platform=${TARGETPLATFORM:-linux/amd64} ghcr.io/openfaas/of-watchdog:0.10.12 AS watchdog
2+
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.25-alpine AS build
33

44
ARG TARGETPLATFORM
55
ARG BUILDPLATFORM
@@ -36,7 +36,7 @@ WORKDIR /go/src/handler
3636
RUN CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} GOFLAGS=${GOFLAGS} \
3737
go build --ldflags "-s -w" -o handler .
3838

39-
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.22.0 AS ship
39+
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.22.2 AS ship
4040
# Add non root user and certs
4141

4242
RUN apk --no-cache add ca-certificates \
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/handler
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.25-alpine AS build
2+
3+
ARG TARGETPLATFORM
4+
ARG BUILDPLATFORM
5+
ARG TARGETOS
6+
ARG TARGETARCH
7+
8+
RUN apk --no-cache add git
9+
10+
RUN mkdir -p /go/src/handler
11+
WORKDIR /go/src/handler
12+
COPY . .
13+
14+
ARG GO111MODULE="on"
15+
ARG GOPROXY=""
16+
ARG GOFLAGS=""
17+
ARG CGO_ENABLED=0
18+
ENV CGO_ENABLED=${CGO_ENABLED}
19+
20+
# Run a gofmt and exclude all vendored code.
21+
RUN test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./function/vendor/*"))" || { echo "Run \"gofmt -s -w\" on your Golang code"; exit 1; }
22+
23+
WORKDIR /go/src/handler/function
24+
RUN mkdir -p /go/src/handler/function/static
25+
26+
RUN --mount=type=cache,target=/root/.cache/go-build \
27+
--mount=type=cache,target=/go/pkg/mod \
28+
GOOS=${TARGETOS} GOARCH=${TARGETARCH} go test ./... -cover
29+
30+
WORKDIR /go/src/handler
31+
RUN --mount=type=cache,target=/root/.cache/go-build \
32+
--mount=type=cache,target=/go/pkg/mod \
33+
GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
34+
go build --ldflags "-s -w" -o handler .
35+
36+
FROM --platform=${TARGETPLATFORM:-linux/amd64} alpine:3.22.1 AS ship
37+
38+
# Add non root user and certs
39+
RUN apk --no-cache add ca-certificates \
40+
&& addgroup -S app && adduser -S -g app app
41+
42+
# Split instructions so that buildkit can run & cache
43+
# the previous command ahead of time.
44+
RUN mkdir -p /home/app \
45+
&& chown app /home/app
46+
47+
WORKDIR /home/app
48+
49+
COPY --from=build --chown=app /go/src/handler/handler .
50+
COPY --from=build --chown=app /go/src/handler/function/static static
51+
52+
USER app
53+
54+
ENV fprocess=""
55+
ENV mode="inproc"
56+
ENV upstream_url=""
57+
ENV prefix_logs="false"
58+
59+
CMD ["./handler"]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module handler/function
2+
3+
go 1.24.0
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package function
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log/slog"
7+
"os"
8+
9+
"net/http"
10+
"time"
11+
)
12+
13+
func Handle(w http.ResponseWriter, r *http.Request) {
14+
var input []byte
15+
16+
log := slog.New(slog.NewTextHandler(os.Stdout, opts))
17+
log = log.With("X-Call-Id", r.Header.Get("X-Call-Id"))
18+
19+
log.Info("received request")
20+
21+
if r.Body != nil {
22+
defer r.Body.Close()
23+
24+
body, _ := io.ReadAll(r.Body)
25+
26+
input = body
27+
}
28+
29+
log.Info("Sleeping for 1 milliseconds")
30+
31+
time.Sleep(time.Millisecond * 1)
32+
33+
log.Info("Sleep done")
34+
35+
w.WriteHeader(http.StatusOK)
36+
w.Write([]byte(fmt.Sprintf("Body: %s", string(input))))
37+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module handler
2+
3+
go 1.24.0
4+
5+
require (
6+
github.com/google/uuid v1.6.0
7+
github.com/openfaas/of-watchdog v0.0.0-20251114100857-67a6309db21b
8+
)
9+
10+
require (
11+
github.com/beorn7/perks v1.0.1 // indirect
12+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
13+
github.com/docker/go-units v0.5.0 // indirect
14+
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
15+
github.com/kylelemons/godebug v1.1.0 // indirect
16+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
17+
github.com/openfaas/faas-middleware v1.2.5 // indirect
18+
github.com/openfaas/faas-provider v0.25.8 // indirect
19+
github.com/prometheus/client_golang v1.23.0 // indirect
20+
github.com/prometheus/client_model v0.6.2 // indirect
21+
github.com/prometheus/common v0.65.0 // indirect
22+
github.com/prometheus/procfs v0.17.0 // indirect
23+
github.com/rakutentech/jwk-go v1.2.0 // indirect
24+
golang.org/x/crypto v0.41.0 // indirect
25+
golang.org/x/sys v0.35.0 // indirect
26+
google.golang.org/protobuf v1.36.7 // indirect
27+
)
28+
29+
// replace github.com/openfaas/of-watchdog => ../../../of-watchdog
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
8+
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
9+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
10+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
11+
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
12+
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
13+
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
14+
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
15+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
16+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
17+
github.com/google/pprof v0.0.0-20250125003558-7fdb3d7e6fa0 h1:my2ucqBZmv+cWHIhZNSIYKzgN8EBGyHdC7zD5sASRAg=
18+
github.com/google/pprof v0.0.0-20250125003558-7fdb3d7e6fa0/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
19+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
20+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
21+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
22+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
23+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
24+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
25+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
26+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
27+
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
28+
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
29+
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
30+
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
31+
github.com/openfaas/faas-middleware v1.2.5 h1:RXPsuXw1PsxPsQ0MJz0ud3mU6X+Rg8v50ZAPxapVJ1g=
32+
github.com/openfaas/faas-middleware v1.2.5/go.mod h1:YuGnJ7wVW/dJEzZCltHYKGGHwfelQMPWt205m6PNfVE=
33+
github.com/openfaas/faas-provider v0.25.8 h1:3W1ZyhUvpqTOiNQoV7jzdZhDJeJJlJelosAtjFzMNyw=
34+
github.com/openfaas/faas-provider v0.25.8/go.mod h1:rMXbj+AYVpn82UoHIOgWHiDeV118t0bSxyoC9d00jpc=
35+
github.com/openfaas/of-watchdog v0.0.0-20251111152958-6696d30d7c8a h1:RInh0UKCMMA8QG40kcDNs4TQHOQcwR3xtcWtO21RsTo=
36+
github.com/openfaas/of-watchdog v0.0.0-20251111152958-6696d30d7c8a/go.mod h1:HjFTzt+rGkPtXEagz6qk3yTuqjJj52UPWeeSF02fosw=
37+
github.com/openfaas/of-watchdog v0.0.0-20251114100857-67a6309db21b h1:xrTwtQQBowj2SAfIHxZjXWddYPlU9Yb9g52XwrJ70s4=
38+
github.com/openfaas/of-watchdog v0.0.0-20251114100857-67a6309db21b/go.mod h1:HjFTzt+rGkPtXEagz6qk3yTuqjJj52UPWeeSF02fosw=
39+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
40+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
41+
github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc=
42+
github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE=
43+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
44+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
45+
github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
46+
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
47+
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
48+
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
49+
github.com/rakutentech/jwk-go v1.2.0 h1:vNJwedPkRR+32V5WGNj0JP4COes93BGERvzQLBjLy4c=
50+
github.com/rakutentech/jwk-go v1.2.0/go.mod h1:pI0bYVntqaJ27RCpaC75MTUacheW0Rk4+8XzWWe1OWM=
51+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
52+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
53+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
54+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
55+
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
56+
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
57+
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
58+
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
59+
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
60+
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
61+
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
62+
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
63+
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
64+
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
65+
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
66+
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
67+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
68+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
go 1.25.0
2+
3+
use (
4+
.
5+
./function
6+
)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"handler/function"
6+
"log"
7+
"net/http"
8+
"os"
9+
"os/signal"
10+
"syscall"
11+
"time"
12+
13+
"github.com/google/uuid"
14+
"github.com/openfaas/of-watchdog/config"
15+
16+
"github.com/openfaas/of-watchdog/pkg"
17+
)
18+
19+
const defaultTimeout = 10 * time.Second
20+
21+
func main() {
22+
23+
os.Setenv("mode", "inproc")
24+
25+
if _, ok := os.LookupEnv("exec_timeout"); !ok {
26+
os.Setenv("exec_timeout", defaultTimeout.String())
27+
}
28+
29+
extendedTimeout := time.Duration(defaultTimeout + time.Millisecond*100)
30+
31+
if _, ok := os.LookupEnv("read_timeout"); !ok {
32+
os.Setenv("read_timeout", extendedTimeout.String())
33+
}
34+
if _, ok := os.LookupEnv("write_timeout"); !ok {
35+
os.Setenv("write_timeout", extendedTimeout.String())
36+
}
37+
38+
if v, ok := os.LookupEnv("healthcheck_interval"); !ok {
39+
os.Setenv("healthcheck_interval", os.Getenv("write_timeout"))
40+
} else {
41+
interval, _ := time.ParseDuration(v)
42+
if interval <= time.Millisecond*0 {
43+
os.Setenv("healthcheck_interval", "1ms")
44+
}
45+
}
46+
47+
cfg, err := config.New(os.Environ())
48+
if err != nil {
49+
log.Fatalf("failed to parse watchdog config: %v", err)
50+
}
51+
52+
log.Printf("Watchdog config: %+v\n", cfg)
53+
54+
h := func(w http.ResponseWriter, r *http.Request) {
55+
if _, ok := r.Header["X-Call-Id"]; !ok {
56+
r.Header.Set("X-Call-Id", uuid.New().String())
57+
}
58+
function.Handle(w, r)
59+
}
60+
61+
cfg.SetHandler(h)
62+
cfg.OperationalMode = config.ModeInproc
63+
64+
watchdog := pkg.NewWatchdog(cfg)
65+
66+
sigs := make(chan os.Signal, 1)
67+
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
68+
ctx, cancel := context.WithCancel(context.Background())
69+
defer cancel()
70+
71+
go func() {
72+
s := <-sigs
73+
log.Printf("Signal received: %s", s.String())
74+
cancel()
75+
}()
76+
77+
if err := watchdog.Start(ctx); err != nil {
78+
log.Fatalf("failed to start watchdog: %v", err)
79+
}
80+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: golang-middleware-inproc
2+
fprocess: ./handler
3+
welcome_message: |
4+
You have created a new function which uses go 1.24 and Alpine
5+
Linux as its base image.
6+
7+
To disable the go module, for private vendor code, please use
8+
"--build-arg GO111MODULE=off" with faas-cli build or configure this
9+
via your stack.yml file.
10+
11+
Learn more: https://docs.openfaas.com/languages/go/

0 commit comments

Comments
 (0)