Skip to content

Instantly share code, notes, and snippets.

@cevin
Created December 24, 2022 10:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cevin/c5a2c47c81b3b6a96e6e0d2d0114b7e1 to your computer and use it in GitHub Desktop.
Save cevin/c5a2c47c81b3b6a96e6e0d2d0114b7e1 to your computer and use it in GitHub Desktop.
test golang with systemd socket load balance
// cnet/net.go
package cnet
import (
"fmt"
"log"
"net"
"os"
"strconv"
"strings"
"syscall"
)
const (
startFd = 3
)
var (
listeners = make(map[string]net.Listener)
)
func init() {
log.Printf("%#v\n", os.Environ())
pid := os.Getenv("LISTEN_PID")
fds, _ := strconv.Atoi(os.Getenv("LISTEN_FDS"))
fdNames := strings.Split(os.Getenv("LISTEN_FDNAMES"), ":")
log.Println(pid, fds, fdNames)
if len(pid) <= 0 || fds <= 0 || len(fdNames) <= 0 {
return
}
for fd := startFd; fd < startFd+fds; fd++ {
syscall.CloseOnExec(fd)
offset := fd - startFd
name := fmt.Sprintf("LISTEN_FD_%d", fd)
if offset < len(fdNames) && len(fdNames[offset]) > 0 {
name = fdNames[offset]
}
log.Printf("PID: %d, FD:%d, uintptr:%v, name:%s\n", os.Getpid(), fd, uintptr(fd), name)
file := os.NewFile(uintptr(fd), name)
ln, err := net.FileListener(file)
if err != nil {
log.Printf("PID: %d, fderr: %s\n", os.Getpid(), err)
}
if listener, ok := ln.(*net.TCPListener); ok {
addrS := listener.Addr().String()
shost, sport, err := net.SplitHostPort(addrS)
log.Printf("PID: %d, FD:%d, addr:%s, sh:%s, sp:%s, se:%s\n", os.Getpid(), fd, addrS, shost, sport, err)
listeners[sport] = ln
} else {
log.Printf("PID: %d, FD:%d, not a TCPListener\n", os.Getpid(), fd)
}
file.Close()
}
log.Printf("%#v\n", listeners)
}
func Listen(addr string) (net.Listener, error) {
_, sport, err := net.SplitHostPort(addr)
if err != nil {
panic(err)
}
if listener, ok := listeners[sport]; ok {
return listener, nil
}
return net.Listen("tcp", addr)
}
package main
import (
"test/cnet"
"fmt"
"log"
"net/http"
"os"
)
func main() {
ln, err := cnet.Listen(":8000")
if err != nil {
log.Printf("PID:%d, err:%s\n", os.Getpid(), err.Error())
os.Exit(1)
}
handler := http.NewServeMux()
handler.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
str := fmt.Sprintf("systemd socket with go, PID:%d", os.Getpid())
_, _ = writer.Write([]byte(str))
})
srv := http.Server{
Handler: handler,
}
log.Printf("PID: %d, started\n", os.Getpid())
err = srv.Serve(ln)
if err != nil {
log.Printf("PID:%d, err:%s\n", os.Getpid(), err.Error())
}
}
[Unit]
Description=test worker for %i
[Service]
Type=simple
ExecStart=/root/test
[Install]
WantedBy=default.target
[Unit]
Description=test for %i
[Socket]
ListenStream=8000
NoDelay=yes
ReusePort=yes
Service=test@%i.service
[Install]
WantedBy=sockets.target
@cevin
Copy link
Author

cevin commented Dec 24, 2022

fail.

The pid output from http does not change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment