Skip to content

Commit 5c0baf8

Browse files
committed
feat: add client connection hang
1 parent e5ad0f3 commit 5c0baf8

File tree

1 file changed

+131
-64
lines changed

1 file changed

+131
-64
lines changed

server/connector.go

Lines changed: 131 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ import (
2525

2626
const (
2727
handshakeTimeout = 5 * time.Second
28-
backendTimeout = 1 * time.Second
28+
backendTimeout = 30 * time.Second
29+
backendRetryInterval = 5 * time.Second
30+
backendStatusTimeout = 1 * time.Second
2931
)
3032

3133
var noDeadline time.Time
@@ -428,7 +430,7 @@ func (c *Connector) cleanupBackendConnection(ctx context.Context, clientAddr net
428430
}
429431

430432
func (c *Connector) findAndConnectBackend(ctx context.Context, frontendConn net.Conn,
431-
clientAddr net.Addr, preReadContent io.Reader, serverAddress string, playerInfo *PlayerInfo, nextState mcproto.State) {
433+
clientAddr net.Addr, preReadContent io.Reader, serverAddress string, playerInfo *PlayerInfo, nextState mcproto.State) {
432434

433435
backendHostPort, resolvedHost, waker, _ := Routes.FindBackendForServerAddress(ctx, serverAddress)
434436
cleanupMetrics := false
@@ -458,72 +460,137 @@ func (c *Connector) findAndConnectBackend(ctx context.Context, frontendConn net.
458460
}
459461
}
460462

461-
if backendHostPort == "" {
463+
if backendHostPort == "" {
464+
logrus.
465+
WithField("serverAddress", serverAddress).
466+
WithField("resolvedHost", resolvedHost).
467+
WithField("player", playerInfo).
468+
Warn("Unable to find registered backend")
469+
c.metrics.Errors.With("type", "missing_backend").Add(1)
470+
471+
if c.connectionNotifier != nil {
472+
err := c.connectionNotifier.NotifyMissingBackend(ctx, clientAddr, serverAddress, playerInfo)
473+
if err != nil {
474+
logrus.WithError(err).Warn("failed to notify missing backend")
475+
}
476+
}
477+
478+
return
479+
}
480+
481+
logrus.
482+
WithField("client", clientAddr).
483+
WithField("server", serverAddress).
484+
WithField("backendHostPort", backendHostPort).
485+
WithField("player", playerInfo).
486+
Info("Connecting to backend")
487+
488+
var backendConn net.Conn
489+
var err error
490+
491+
if nextState == mcproto.StateStatus {
492+
// Status request: try to connect once with backendStatusTimeout
493+
backendConn, err = net.DialTimeout("tcp", backendHostPort, backendStatusTimeout)
494+
if err != nil {
495+
logrus.
496+
WithError(err).
497+
WithField("client", clientAddr).
498+
WithField("serverAddress", serverAddress).
499+
WithField("backend", backendHostPort).
500+
WithField("player", playerInfo).
501+
Warn("Unable to connect to backend for status request")
502+
c.metrics.Errors.With("type", "backend_failed").Add(1)
503+
504+
if c.connectionNotifier != nil {
505+
notifyErr := c.connectionNotifier.NotifyFailedBackendConnection(ctx, clientAddr, serverAddress, playerInfo, backendHostPort, err)
506+
if notifyErr != nil {
507+
logrus.WithError(notifyErr).Warn("failed to notify failed backend connection")
508+
}
509+
}
510+
511+
// Return fakeOnline MOTD
512+
if c.fakeOnline && waker != nil {
513+
logrus.Info("Server is offline, sending fakeOnlineMOTD for status request")
514+
writeStatusErr := mcproto.WriteStatusResponse(
515+
frontendConn,
516+
c.fakeOnlineMOTD,
517+
)
518+
if writeStatusErr != nil {
519+
logrus.
520+
WithError(writeStatusErr).
521+
WithField("client", clientAddr).
522+
WithField("serverAddress", serverAddress).
523+
WithField("backend", backendHostPort).
524+
WithField("player", playerInfo).
525+
Error("Failed to write status response")
526+
}
527+
}
528+
return
529+
}
530+
} else if nextState == mcproto.StateLogin {
531+
// Connect request
532+
if waker != nil {
533+
logrus.Debug("Connect: Autoscaler is enabled, waiting for backend to be ready")
534+
// Autoscaler enabled: retry until backendTimeout is reached
535+
deadline := time.Now().Add(backendTimeout)
536+
for {
537+
backendConn, err = net.DialTimeout("tcp", backendHostPort, backendRetryInterval)
538+
logrus.Debug("Tries to connect to backend")
539+
540+
if err == nil {
541+
break
542+
}
543+
if time.Now().After(deadline) {
544+
logrus.
545+
WithError(err).
546+
WithField("client", clientAddr).
547+
WithField("serverAddress", serverAddress).
548+
WithField("backend", backendHostPort).
549+
WithField("player", playerInfo).
550+
Warn("Unable to connect to backend after retries (autoscaler enabled)")
551+
c.metrics.Errors.With("type", "backend_failed").Add(1)
552+
if c.connectionNotifier != nil {
553+
notifyErr := c.connectionNotifier.NotifyFailedBackendConnection(ctx, clientAddr, serverAddress, playerInfo, backendHostPort, err)
554+
if notifyErr != nil {
555+
logrus.WithError(notifyErr).Warn("failed to notify failed backend connection")
556+
}
557+
}
558+
return
559+
}
560+
time.Sleep(backendRetryInterval)
561+
}
562+
} else {
563+
logrus.Debug("Connect: Autoscaler is disabled, trying to connect once")
564+
// Autoscaler disabled: try to connect once with backendTimeout
565+
backendConn, err = net.DialTimeout("tcp", backendHostPort, backendTimeout)
566+
if err != nil {
567+
logrus.
568+
WithError(err).
569+
WithField("client", clientAddr).
570+
WithField("serverAddress", serverAddress).
571+
WithField("backend", backendHostPort).
572+
WithField("player", playerInfo).
573+
Warn("Unable to connect to backend (autoscaler disabled)")
574+
c.metrics.Errors.With("type", "backend_failed").Add(1)
575+
if c.connectionNotifier != nil {
576+
notifyErr := c.connectionNotifier.NotifyFailedBackendConnection(ctx, clientAddr, serverAddress, playerInfo, backendHostPort, err)
577+
if notifyErr != nil {
578+
logrus.WithError(notifyErr).Warn("failed to notify failed backend connection")
579+
}
580+
}
581+
return
582+
}
583+
}
584+
} else {
585+
// Unknown state, do nothing
462586
logrus.
463-
WithField("serverAddress", serverAddress).
464-
WithField("resolvedHost", resolvedHost).
465-
WithField("player", playerInfo).
466-
Warn("Unable to find registered backend")
467-
c.metrics.Errors.With("type", "missing_backend").Add(1)
468-
469-
if c.connectionNotifier != nil {
470-
err := c.connectionNotifier.NotifyMissingBackend(ctx, clientAddr, serverAddress, playerInfo)
471-
if err != nil {
472-
logrus.WithError(err).Warn("failed to notify missing backend")
473-
}
474-
}
475-
476-
return
477-
}
478-
479-
logrus.
480-
WithField("client", clientAddr).
481-
WithField("server", serverAddress).
482-
WithField("backendHostPort", backendHostPort).
483-
WithField("player", playerInfo).
484-
Info("Connecting to backend")
485-
486-
backendConn, err := net.DialTimeout("tcp", backendHostPort, backendTimeout)
487-
if err != nil {
488-
logrus.
489-
WithError(err).
490587
WithField("client", clientAddr).
491588
WithField("serverAddress", serverAddress).
492-
WithField("backend", backendHostPort).
589+
WithField("nextState", nextState).
493590
WithField("player", playerInfo).
494-
Warn("Unable to connect to backend")
495-
c.metrics.Errors.With("type", "backend_failed").Add(1)
496-
497-
if c.connectionNotifier != nil {
498-
notifyErr := c.connectionNotifier.NotifyFailedBackendConnection(ctx, clientAddr, serverAddress, playerInfo, backendHostPort, err)
499-
if notifyErr != nil {
500-
logrus.WithError(notifyErr).Warn("failed to notify failed backend connection")
501-
}
502-
}
503-
504-
// Verify that the packet is a status request && autoScaleUp is enabled
505-
if c.fakeOnline && waker != nil && nextState == mcproto.StateStatus {
506-
logrus.Info("Server is offline, sending fakeOnlineMOTD")
507-
508-
// Send a response to the client indicating that the server is sleeping
509-
writeStatusErr := mcproto.WriteStatusResponse(
510-
frontendConn,
511-
c.fakeOnlineMOTD,
512-
)
513-
514-
if writeStatusErr != nil {
515-
logrus.
516-
WithError(writeStatusErr).
517-
WithField("client", clientAddr).
518-
WithField("serverAddress", serverAddress).
519-
WithField("backend", backendHostPort).
520-
WithField("player", playerInfo).
521-
Error("Failed to write status response")
522-
}
523-
}
524-
525-
return
526-
}
591+
Warn("Unknown state, unable to connect to backend")
592+
return
593+
}
527594

528595
if c.connectionNotifier != nil {
529596
err := c.connectionNotifier.NotifyConnected(ctx, clientAddr, serverAddress, playerInfo, backendHostPort)

0 commit comments

Comments
 (0)