Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 57 additions & 29 deletions server/internal/plugins/scaletozero/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,30 @@ func NewManager(
}

type Manager struct {
logger zerolog.Logger
config *Config
sessions types.SessionManager
ctrl scaletozero.Controller
mu sync.Mutex
shutdown bool
pending int
logger zerolog.Logger
config *Config
sessions types.SessionManager
ctrl scaletozero.Controller
mu sync.Mutex
shutdown bool
disabledScaleToZero bool
}

func (m *Manager) Start() error {
if !m.config.Enabled {
return nil
}
m.logger.Info().Msg("scale-to-zero plugin enabled")
m.logger.Info().Msg("plugin enabled")

m.sessions.OnConnected(func(session types.Session) {
m.mu.Lock()
defer m.mu.Unlock()
if m.shutdown {
return
}
// compute initial state and toggle if needed
m.manage()

m.pending++
m.logger.Info().Msgf("connection started, disabling scale-to-zero (pending: %d)", m.pending)
m.ctrl.Disable(context.Background())
m.sessions.OnConnected(func(session types.Session) {
m.manage()
})

m.sessions.OnDisconnected(func(session types.Session) {
m.mu.Lock()
defer m.mu.Unlock()
if m.shutdown {
return
}

m.pending--
m.logger.Info().Msgf("connection started, disabling scale-to-zero (pending: %d)", m.pending)
m.ctrl.Enable(context.Background())
m.manage()
})

return nil
Expand All @@ -72,10 +59,51 @@ func (m *Manager) Shutdown() error {
defer m.mu.Unlock()
m.shutdown = true

m.logger.Info().Msgf("shutdown started, re-enabling scale-to-zero (pending: %d)", m.pending)
for i := 0; i < m.pending; i++ {
m.ctrl.Enable(context.Background())
if m.disabledScaleToZero {
return m.ctrl.Enable(context.Background())
}

return nil
}

func (m *Manager) manage() {
m.mu.Lock()
defer m.mu.Unlock()

if m.shutdown {
return
}

connectedSessions := 0
for _, s := range m.sessions.List() {
if s.State().IsConnected {
connectedSessions++
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a world where a session is disconnected (IsConnected == false) but is trying to reconnect, and by not counting it here we might scale to zero, preventing it from connecting?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question! There's a grace period after disconnects for reconnection: https://github.com/onkernel/neko/blob/e9293ae098832ae0c4b63d092a9bd370e3c0ab12/server/internal/session/session.go#L145-L213

Especially wrt to scale to zero that delay + this buffer seems reasonable. For new connections at our proxy layer we'd be "waking up" the VM externally regardless ^^

}
}
hasConnectedSessions := connectedSessions > 0

if hasConnectedSessions == m.disabledScaleToZero {
m.logger.Info().Bool("previously_disabled", m.disabledScaleToZero).
Bool("currently_disabled", hasConnectedSessions).
Int("currently_connected_sessions", connectedSessions).
Msg("no operation needed; skipping toggle")
return
}

// toggle if needed but only update internal state if successful
if hasConnectedSessions {
m.logger.Info().Int("connected_sessions", connectedSessions).Msg("disabling scale-to-zero")
if err := m.ctrl.Disable(context.Background()); err != nil {
m.logger.Error().Err(err).Msg("failed to disable scale-to-zero")
return
}
} else {
m.logger.Info().Msg("enabling scale-to-zero")
if err := m.ctrl.Enable(context.Background()); err != nil {
m.logger.Error().Err(err).Msg("failed to enable scale-to-zero")
return
}
}

m.disabledScaleToZero = hasConnectedSessions
}