Skip to content

Commit b135766

Browse files
authored
Proxy health check (#381)
1 parent 91f35ae commit b135766

File tree

3 files changed

+33
-5
lines changed

3 files changed

+33
-5
lines changed

cmd/litefs/config.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ func NewConfig() Config {
5757

5858
config.Log.Format = "text"
5959

60+
config.Proxy.MaxLag = http.DefaultMaxLag
61+
6062
config.Tracing.Enabled = true
6163
config.Tracing.MaxSize = DefaultTracingMaxSize
6264
config.Tracing.MaxCount = DefaultTracingMaxCount
@@ -110,11 +112,12 @@ type HTTPConfig struct {
110112

111113
// ProxyConfig represents the configuration for the HTTP proxy server.
112114
type ProxyConfig struct {
113-
Addr string `yaml:"addr"`
114-
Target string `yaml:"target"`
115-
DB string `yaml:"db"`
116-
Debug bool `yaml:"debug"`
117-
Passthrough []string `yaml:"passthrough"`
115+
Addr string `yaml:"addr"`
116+
Target string `yaml:"target"`
117+
DB string `yaml:"db"`
118+
MaxLag time.Duration `yaml:"max-lag"`
119+
Debug bool `yaml:"debug"`
120+
Passthrough []string `yaml:"passthrough"`
118121
}
119122

120123
// LeaseConfig represents a generic configuration for all lease types.

cmd/litefs/mount_linux.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ func (c *MountCommand) runProxyServer(ctx context.Context) error {
503503
server.Target = c.Config.Proxy.Target
504504
server.DBName = c.Config.Proxy.DB
505505
server.Addr = c.Config.Proxy.Addr
506+
server.MaxLag = c.Config.Proxy.MaxLag
506507
server.Debug = c.Config.Proxy.Debug
507508
server.Passthroughs = passthroughs
508509
if err := server.Listen(); err != nil {

http/proxy_server.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const (
2424
DefaultPollTXIDInterval = 1 * time.Millisecond
2525
DefaultPollTXIDTimeout = 5 * time.Second
2626

27+
DefaultMaxLag = 10 * time.Second
28+
2729
DefaultCookieExpiry = 5 * time.Minute
2830
)
2931

@@ -61,6 +63,9 @@ type ProxyServer struct {
6163
PollTXIDInterval time.Duration
6264
PollTXIDTimeout time.Duration
6365

66+
// Maximum allowable lag before the health endpoint returns an error code.
67+
MaxLag time.Duration
68+
6469
// Time before cookie expires on client.
6570
CookieExpiry time.Duration
6671

@@ -74,6 +79,7 @@ func NewProxyServer(store *litefs.Store) *ProxyServer {
7479

7580
PollTXIDInterval: DefaultPollTXIDInterval,
7681
PollTXIDTimeout: DefaultPollTXIDTimeout,
82+
MaxLag: DefaultMaxLag,
7783
CookieExpiry: DefaultCookieExpiry,
7884
}
7985

@@ -167,6 +173,12 @@ func (s *ProxyServer) serveHTTP(w http.ResponseWriter, r *http.Request) {
167173
return
168174
}
169175

176+
// Handle health check endpoint.
177+
if r.Method == http.MethodGet && r.URL.Path == "/litefs/healthz" {
178+
s.serveGetHealthz(w, r)
179+
return
180+
}
181+
170182
switch r.Method {
171183
case http.MethodGet:
172184
s.serveRead(w, r)
@@ -177,6 +189,18 @@ func (s *ProxyServer) serveHTTP(w http.ResponseWriter, r *http.Request) {
177189
}
178190
}
179191

192+
func (s *ProxyServer) serveGetHealthz(w http.ResponseWriter, r *http.Request) {
193+
lag := s.store.Lag()
194+
if s.MaxLag > 0 && lag > s.MaxLag {
195+
s.logf("proxy: %s %s: current replication lag of %s exceeds maximum threshold of %s", r.Method, r.URL.Path, lag, s.MaxLag)
196+
http.Error(w, "Replication lag exceeded", http.StatusServiceUnavailable)
197+
return
198+
}
199+
200+
w.WriteHeader(http.StatusOK)
201+
_, _ = w.Write([]byte("OK\n"))
202+
}
203+
180204
func (s *ProxyServer) serveRead(w http.ResponseWriter, r *http.Request) {
181205
// Determine the last write TXID seen by
182206
var txid ltx.TXID

0 commit comments

Comments
 (0)