-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
agent: Rewrite scaling logic into pkg/agent/{core,executor}
At a very high level, this work replaces (*Runner).handleVMResources(), moving from an imperative style to an explicit state machine. This new version is more complicated, but ultimately more flexible and easier to extend. The decision-making "core" of the scaling logic is implemented by (*core.State).NextActions(), which returns an ActionSet indicating what the "caller" should do. NextActions() is a pure function, making this easier to test - at least, in theory. That method is called and cached by executor.ExecutorCore, where there's a few different threads (each defined in exec_*.go) responsible for implementing the communications with the other components - namely, the scheduler plugin, vm-informant, and NeonVM k8s API. The various "executor" threads are written generically, using dedicated interfaces (e.g. PluginInterface / PluginHandle) that are implemented in pkg/agent/execbridge.go.
- Loading branch information
Showing
18 changed files
with
2,136 additions
and
1,045 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package core | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/neondatabase/autoscaling/pkg/api" | ||
) | ||
|
||
type ActionSet struct { | ||
Wait *ActionWait `json:"wait,omitempty"` | ||
PluginRequest *ActionPluginRequest `json:"pluginRequest,omitempty"` | ||
NeonVMRequest *ActionNeonVMRequest `json:"neonvmRequest,omitempty"` | ||
InformantDownscale *ActionInformantDownscale `json:"informantDownscale,omitempty"` | ||
InformantUpscale *ActionInformantUpscale `json:"informantUpscale,omitempty"` | ||
} | ||
|
||
type ActionWait struct { | ||
Duration time.Duration `json:"duration"` | ||
} | ||
|
||
type ActionPluginRequest struct { | ||
LastPermit *api.Resources `json:"current"` | ||
Target api.Resources `json:"target"` | ||
Metrics *api.Metrics `json:"metrics"` | ||
} | ||
|
||
type ActionNeonVMRequest struct { | ||
Current api.Resources `json:"current"` | ||
Target api.Resources `json:"target"` | ||
} | ||
|
||
type ActionInformantDownscale struct { | ||
Current api.Resources `json:"current"` | ||
Target api.Resources `json:"target"` | ||
} | ||
|
||
type ActionInformantUpscale struct { | ||
Current api.Resources `json:"current"` | ||
Target api.Resources `json:"target"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package core | ||
|
||
// Implementation of (*UpdateState).Dump() | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/neondatabase/autoscaling/pkg/api" | ||
) | ||
|
||
func shallowCopy[T any](ptr *T) *T { | ||
if ptr == nil { | ||
return nil | ||
} else { | ||
x := *ptr | ||
return &x | ||
} | ||
} | ||
|
||
// StateDump provides introspection into the current values of the fields of State | ||
type StateDump struct { | ||
Config Config `json:"config"` | ||
VM api.VmInfo `json:"vm"` | ||
Plugin pluginStateDump `json:"plugin"` | ||
Informant informantStateDump `json:"informant"` | ||
NeonVM neonvmStateDump `json:"neonvm"` | ||
Metrics *api.Metrics `json:"metrics"` | ||
} | ||
|
||
// Dump produces a JSON-serializable representation of the State | ||
func (s *State) Dump() StateDump { | ||
return StateDump{ | ||
Config: s.config, | ||
VM: s.vm, | ||
Plugin: s.plugin.dump(), | ||
Informant: s.informant.dump(), | ||
NeonVM: s.neonvm.dump(), | ||
Metrics: shallowCopy(s.metrics), | ||
} | ||
} | ||
|
||
type pluginStateDump struct { | ||
Alive bool `json:"alive"` | ||
OngoingRequest bool `json:"ongoingRequest"` | ||
ComputeUnit *api.Resources `json:"computeUnit"` | ||
LastRequest *pluginRequestedDump `json:"lastRequest"` | ||
Permit *api.Resources `json:"permit"` | ||
} | ||
type pluginRequestedDump struct { | ||
At time.Time `json:"time"` | ||
Resources api.Resources `json:"resources"` | ||
} | ||
|
||
func (s *pluginState) dump() pluginStateDump { | ||
var lastRequest *pluginRequestedDump | ||
if s.lastRequest != nil { | ||
lastRequest = &pluginRequestedDump{ | ||
At: s.lastRequest.at, | ||
Resources: s.lastRequest.resources, | ||
} | ||
} | ||
|
||
return pluginStateDump{ | ||
Alive: s.alive, | ||
OngoingRequest: s.ongoingRequest, | ||
ComputeUnit: shallowCopy(s.computeUnit), | ||
LastRequest: lastRequest, | ||
Permit: shallowCopy(s.permit), | ||
} | ||
} | ||
|
||
type informantStateDump struct { | ||
Active bool `json:"active"` | ||
OngoingRequest *OngoingInformantRequestDump `json:"ongoingRequest"` | ||
RequestedUpscale *requestedUpscaleDump `json:"requestedUpscale"` | ||
DeniedDownscale *deniedDownscaleDump `json:"deniedDownscale"` | ||
Approved *api.Resources `json:"approved"` | ||
DownscaleFailureAt *time.Time `json:"downscaleFailureAt"` | ||
UpscaleFailureAt *time.Time `json:"upscaleFailureAt"` | ||
} | ||
type OngoingInformantRequestDump struct { | ||
Kind informantRequestKind `json:"kind"` | ||
} | ||
type requestedUpscaleDump struct { | ||
At time.Time `json:"at"` | ||
Base api.Resources `json:"base"` | ||
Requested api.MoreResources `json:"requested"` | ||
} | ||
type deniedDownscaleDump struct { | ||
At time.Time `json:"at"` | ||
Requested api.Resources `json:"requested"` | ||
} | ||
|
||
func (s *informantState) dump() informantStateDump { | ||
var requestedUpscale *requestedUpscaleDump | ||
if s.requestedUpscale != nil { | ||
requestedUpscale = &requestedUpscaleDump{ | ||
At: s.requestedUpscale.at, | ||
Base: s.requestedUpscale.base, | ||
Requested: s.requestedUpscale.requested, | ||
} | ||
} | ||
|
||
var deniedDownscale *deniedDownscaleDump | ||
if s.deniedDownscale != nil { | ||
deniedDownscale = &deniedDownscaleDump{ | ||
At: s.deniedDownscale.at, | ||
Requested: s.deniedDownscale.requested, | ||
} | ||
} | ||
|
||
var ongoingRequest *OngoingInformantRequestDump | ||
if s.ongoingRequest != nil { | ||
ongoingRequest = &OngoingInformantRequestDump{ | ||
Kind: s.ongoingRequest.kind, | ||
} | ||
} | ||
|
||
return informantStateDump{ | ||
Active: s.active, | ||
OngoingRequest: ongoingRequest, | ||
RequestedUpscale: requestedUpscale, | ||
DeniedDownscale: deniedDownscale, | ||
Approved: shallowCopy(s.approved), | ||
DownscaleFailureAt: shallowCopy(s.downscaleFailureAt), | ||
UpscaleFailureAt: shallowCopy(s.upscaleFailureAt), | ||
} | ||
} | ||
|
||
type neonvmStateDump struct { | ||
LastSuccess *api.Resources `json:"lastSuccess"` | ||
OngoingRequested *api.Resources `json:"ongoingRequested"` | ||
RequestFailedAt *time.Time `json:"requestFailedAt"` | ||
} | ||
|
||
func (s *neonvmState) dump() neonvmStateDump { | ||
return neonvmStateDump{ | ||
LastSuccess: shallowCopy(s.lastSuccess), | ||
OngoingRequested: shallowCopy(s.ongoingRequested), | ||
RequestFailedAt: shallowCopy(s.requestFailedAt), | ||
} | ||
} |
Oops, something went wrong.