@@ -25,7 +25,9 @@ import (
2525
2626const (
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
3133var noDeadline time.Time
@@ -355,92 +357,157 @@ func (c *Connector) readPlayerInfo(bufferedReader *bufio.Reader, clientAddr net.
355357}
356358
357359func (c * Connector ) findAndConnectBackend (ctx context.Context , frontendConn net.Conn ,
358- clientAddr net.Addr , preReadContent io.Reader , serverAddress string , playerInfo * PlayerInfo , nextState mcproto.State ) {
359-
360- backendHostPort , resolvedHost , waker := Routes .FindBackendForServerAddress (ctx , serverAddress )
361- if waker != nil && nextState > mcproto .StateStatus {
362- serverAllowsPlayer := c .autoScaleUpAllowDenyConfig .ServerAllowsPlayer (serverAddress , playerInfo )
363- logrus .
364- WithField ("client" , clientAddr ).
365- WithField ("server" , serverAddress ).
366- WithField ("player" , playerInfo ).
367- WithField ("serverAllowsPlayer" , serverAllowsPlayer ).
368- Debug ("checked if player is allowed to wake up the server" )
369- if serverAllowsPlayer {
370- if err := waker (ctx ); err != nil {
371- logrus .WithFields (logrus.Fields {"serverAddress" : serverAddress }).WithError (err ).Error ("failed to wake up backend" )
372- c .metrics .Errors .With ("type" , "wakeup_failed" ).Add (1 )
373- return
374- }
375- }
376- }
377-
378- if backendHostPort == "" {
379- logrus .
380- WithField ("serverAddress" , serverAddress ).
381- WithField ("resolvedHost" , resolvedHost ).
382- WithField ("player" , playerInfo ).
383- Warn ("Unable to find registered backend" )
384- c .metrics .Errors .With ("type" , "missing_backend" ).Add (1 )
385-
386- if c .connectionNotifier != nil {
387- err := c .connectionNotifier .NotifyMissingBackend (ctx , clientAddr , serverAddress , playerInfo )
388- if err != nil {
389- logrus .WithError (err ).Warn ("failed to notify missing backend" )
390- }
391- }
392-
393- return
394- }
395-
396- logrus .
397- WithField ("client" , clientAddr ).
398- WithField ("server" , serverAddress ).
399- WithField ("backendHostPort" , backendHostPort ).
400- WithField ("player" , playerInfo ).
401- Info ("Connecting to backend" )
402-
403- backendConn , err := net .DialTimeout ("tcp" , backendHostPort , backendTimeout )
404- if err != nil {
360+ clientAddr net.Addr , preReadContent io.Reader , serverAddress string , playerInfo * PlayerInfo , nextState mcproto.State ) {
361+
362+ backendHostPort , resolvedHost , waker := Routes .FindBackendForServerAddress (ctx , serverAddress )
363+ if waker != nil && nextState > mcproto .StateStatus {
364+ serverAllowsPlayer := c .autoScaleUpAllowDenyConfig .ServerAllowsPlayer (serverAddress , playerInfo )
365+ logrus .
366+ WithField ("client" , clientAddr ).
367+ WithField ("server" , serverAddress ).
368+ WithField ("player" , playerInfo ).
369+ WithField ("serverAllowsPlayer" , serverAllowsPlayer ).
370+ Debug ("checked if player is allowed to wake up the server" )
371+ if serverAllowsPlayer {
372+ if err := waker (ctx ); err != nil {
373+ logrus .WithFields (logrus.Fields {"serverAddress" : serverAddress }).WithError (err ).Error ("failed to wake up backend" )
374+ c .metrics .Errors .With ("type" , "wakeup_failed" ).Add (1 )
375+ return
376+ }
377+ }
378+ }
379+
380+ if backendHostPort == "" {
381+ logrus .
382+ WithField ("serverAddress" , serverAddress ).
383+ WithField ("resolvedHost" , resolvedHost ).
384+ WithField ("player" , playerInfo ).
385+ Warn ("Unable to find registered backend" )
386+ c .metrics .Errors .With ("type" , "missing_backend" ).Add (1 )
387+
388+ if c .connectionNotifier != nil {
389+ err := c .connectionNotifier .NotifyMissingBackend (ctx , clientAddr , serverAddress , playerInfo )
390+ if err != nil {
391+ logrus .WithError (err ).Warn ("failed to notify missing backend" )
392+ }
393+ }
394+
395+ return
396+ }
397+
398+ logrus .
399+ WithField ("client" , clientAddr ).
400+ WithField ("server" , serverAddress ).
401+ WithField ("backendHostPort" , backendHostPort ).
402+ WithField ("player" , playerInfo ).
403+ Info ("Connecting to backend" )
404+
405+ var backendConn net.Conn
406+ var err error
407+
408+ if nextState == mcproto .StateStatus {
409+ // Status request: try to connect once with backendStatusTimeout
410+ backendConn , err = net .DialTimeout ("tcp" , backendHostPort , backendStatusTimeout )
411+ if err != nil {
412+ logrus .
413+ WithError (err ).
414+ WithField ("client" , clientAddr ).
415+ WithField ("serverAddress" , serverAddress ).
416+ WithField ("backend" , backendHostPort ).
417+ WithField ("player" , playerInfo ).
418+ Warn ("Unable to connect to backend for status request" )
419+ c .metrics .Errors .With ("type" , "backend_failed" ).Add (1 )
420+
421+ if c .connectionNotifier != nil {
422+ notifyErr := c .connectionNotifier .NotifyFailedBackendConnection (ctx , clientAddr , serverAddress , playerInfo , backendHostPort , err )
423+ if notifyErr != nil {
424+ logrus .WithError (notifyErr ).Warn ("failed to notify failed backend connection" )
425+ }
426+ }
427+
428+ // Return fakeOnline MOTD
429+ if c .fakeOnline && waker != nil {
430+ logrus .Info ("Server is offline, sending fakeOnlineMOTD for status request" )
431+ writeStatusErr := mcproto .WriteStatusResponse (
432+ frontendConn ,
433+ c .fakeOnlineMOTD ,
434+ )
435+ if writeStatusErr != nil {
436+ logrus .
437+ WithError (writeStatusErr ).
438+ WithField ("client" , clientAddr ).
439+ WithField ("serverAddress" , serverAddress ).
440+ WithField ("backend" , backendHostPort ).
441+ WithField ("player" , playerInfo ).
442+ Error ("Failed to write status response" )
443+ }
444+ }
445+ return
446+ }
447+ } else if nextState == mcproto .StateLogin {
448+ // Connect request
449+ if waker != nil {
450+ logrus .Debug ("Connect: Autoscaler is enabled, waiting for backend to be ready" )
451+ // Autoscaler enabled: retry until backendTimeout is reached
452+ deadline := time .Now ().Add (backendTimeout )
453+ for {
454+ backendConn , err = net .DialTimeout ("tcp" , backendHostPort , backendRetryInterval )
455+ logrus .Debug ("Tries to connect to backend" )
456+
457+ if err == nil {
458+ break
459+ }
460+ if time .Now ().After (deadline ) {
461+ logrus .
462+ WithError (err ).
463+ WithField ("client" , clientAddr ).
464+ WithField ("serverAddress" , serverAddress ).
465+ WithField ("backend" , backendHostPort ).
466+ WithField ("player" , playerInfo ).
467+ Warn ("Unable to connect to backend after retries (autoscaler enabled)" )
468+ c .metrics .Errors .With ("type" , "backend_failed" ).Add (1 )
469+ if c .connectionNotifier != nil {
470+ notifyErr := c .connectionNotifier .NotifyFailedBackendConnection (ctx , clientAddr , serverAddress , playerInfo , backendHostPort , err )
471+ if notifyErr != nil {
472+ logrus .WithError (notifyErr ).Warn ("failed to notify failed backend connection" )
473+ }
474+ }
475+ return
476+ }
477+ time .Sleep (backendRetryInterval )
478+ }
479+ } else {
480+ logrus .Debug ("Connect: Autoscaler is disabled, trying to connect once" )
481+ // Autoscaler disabled: try to connect once with backendTimeout
482+ backendConn , err = net .DialTimeout ("tcp" , backendHostPort , backendTimeout )
483+ if err != nil {
484+ logrus .
485+ WithError (err ).
486+ WithField ("client" , clientAddr ).
487+ WithField ("serverAddress" , serverAddress ).
488+ WithField ("backend" , backendHostPort ).
489+ WithField ("player" , playerInfo ).
490+ Warn ("Unable to connect to backend (autoscaler disabled)" )
491+ c .metrics .Errors .With ("type" , "backend_failed" ).Add (1 )
492+ if c .connectionNotifier != nil {
493+ notifyErr := c .connectionNotifier .NotifyFailedBackendConnection (ctx , clientAddr , serverAddress , playerInfo , backendHostPort , err )
494+ if notifyErr != nil {
495+ logrus .WithError (notifyErr ).Warn ("failed to notify failed backend connection" )
496+ }
497+ }
498+ return
499+ }
500+ }
501+ } else {
502+ // Unknown state, do nothing
405503 logrus .
406- WithError (err ).
407504 WithField ("client" , clientAddr ).
408505 WithField ("serverAddress" , serverAddress ).
409- WithField ("backend " , backendHostPort ).
506+ WithField ("nextState " , nextState ).
410507 WithField ("player" , playerInfo ).
411- Warn ("Unable to connect to backend" )
412- c .metrics .Errors .With ("type" , "backend_failed" ).Add (1 )
413-
414- if c .connectionNotifier != nil {
415- notifyErr := c .connectionNotifier .NotifyFailedBackendConnection (ctx , clientAddr , serverAddress , playerInfo , backendHostPort , err )
416- if notifyErr != nil {
417- logrus .WithError (notifyErr ).Warn ("failed to notify failed backend connection" )
418- }
419- }
420-
421- // Verify that the packet is a status request && autoScaleUp is enabled
422- if c .fakeOnline && waker != nil && nextState == mcproto .StateStatus {
423- logrus .Info ("Server is offline, sending fakeOnlineMOTD" )
424-
425- // Send a response to the client indicating that the server is sleeping
426- writeStatusErr := mcproto .WriteStatusResponse (
427- frontendConn ,
428- c .fakeOnlineMOTD ,
429- )
430-
431- if writeStatusErr != nil {
432- logrus .
433- WithError (writeStatusErr ).
434- WithField ("client" , clientAddr ).
435- WithField ("serverAddress" , serverAddress ).
436- WithField ("backend" , backendHostPort ).
437- WithField ("player" , playerInfo ).
438- Error ("Failed to write status response" )
439- }
440- }
441-
442- return
443- }
508+ Warn ("Unknown state, unable to connect to backend" )
509+ return
510+ }
444511
445512 if c .connectionNotifier != nil {
446513 err := c .connectionNotifier .NotifyConnected (ctx , clientAddr , serverAddress , playerInfo , backendHostPort )
0 commit comments