mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
* fn: paused and evicted container stats With this change, now stats reports paused state as well as incidents of container exit due to evictions. * fn: update/document state transitions in state tracker There's no case of a transition moving from done to waiting. This must be deprecated behavior.
163 lines
3.8 KiB
Go
163 lines
3.8 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.opencensus.io/stats"
|
|
)
|
|
|
|
type RequestStateType int
|
|
type ContainerStateType int
|
|
|
|
type containerState struct {
|
|
lock sync.Mutex
|
|
state ContainerStateType
|
|
start time.Time
|
|
}
|
|
|
|
type requestState struct {
|
|
lock sync.Mutex
|
|
state RequestStateType
|
|
start time.Time
|
|
}
|
|
|
|
type ContainerState interface {
|
|
UpdateState(ctx context.Context, newState ContainerStateType, slots *slotQueue)
|
|
}
|
|
type RequestState interface {
|
|
UpdateState(ctx context.Context, newState RequestStateType, slots *slotQueue)
|
|
}
|
|
|
|
func NewRequestState() RequestState {
|
|
return &requestState{}
|
|
}
|
|
|
|
func NewContainerState() ContainerState {
|
|
return &containerState{}
|
|
}
|
|
|
|
const (
|
|
RequestStateNone RequestStateType = iota // uninitialized
|
|
RequestStateWait // request is waiting
|
|
RequestStateExec // request is executing
|
|
RequestStateDone // request is done
|
|
RequestStateMax
|
|
)
|
|
|
|
const (
|
|
ContainerStateNone ContainerStateType = iota // uninitialized
|
|
ContainerStateWait // resource (cpu + mem) waiting
|
|
ContainerStateStart // launching
|
|
ContainerStateIdle // running: idle but not paused
|
|
ContainerStatePaused // running: idle but paused
|
|
ContainerStateBusy // running: busy
|
|
ContainerStateDone // exited/failed/done
|
|
ContainerStateMax
|
|
)
|
|
|
|
var containerGaugeKeys = [ContainerStateMax]string{
|
|
"",
|
|
"container_wait_total",
|
|
"container_start_total",
|
|
"container_idle_total",
|
|
"container_paused_total",
|
|
"container_busy_total",
|
|
}
|
|
|
|
var containerTimeKeys = [ContainerStateMax]string{
|
|
"",
|
|
"container_wait_duration_seconds",
|
|
"container_start_duration_seconds",
|
|
"container_idle_duration_seconds",
|
|
"container_paused_duration_seconds",
|
|
"container_busy_duration_seconds",
|
|
}
|
|
|
|
func (c *requestState) UpdateState(ctx context.Context, newState RequestStateType, slots *slotQueue) {
|
|
|
|
var now time.Time
|
|
var oldState RequestStateType
|
|
|
|
c.lock.Lock()
|
|
|
|
// we can only advance our state forward
|
|
if c.state < newState {
|
|
|
|
now = time.Now()
|
|
oldState = c.state
|
|
c.state = newState
|
|
c.start = now
|
|
}
|
|
|
|
c.lock.Unlock()
|
|
|
|
if now.IsZero() {
|
|
return
|
|
}
|
|
|
|
// reflect this change to slot mgr if defined (AKA hot)
|
|
if slots != nil {
|
|
slots.enterRequestState(newState)
|
|
slots.exitRequestState(oldState)
|
|
}
|
|
}
|
|
|
|
func isIdleState(state ContainerStateType) bool {
|
|
return state == ContainerStateIdle || state == ContainerStatePaused
|
|
}
|
|
|
|
func (c *containerState) UpdateState(ctx context.Context, newState ContainerStateType, slots *slotQueue) {
|
|
|
|
var now time.Time
|
|
var oldState ContainerStateType
|
|
var before time.Time
|
|
|
|
c.lock.Lock()
|
|
|
|
// Only the following state transitions are allowed:
|
|
// 1) any move forward in states as per ContainerStateType order
|
|
// 2) move back: from paused to idle
|
|
// 3) move back: from busy to idle/paused
|
|
if c.state < newState ||
|
|
(c.state == ContainerStatePaused && newState == ContainerStateIdle) ||
|
|
(c.state == ContainerStateBusy && isIdleState(newState)) {
|
|
|
|
now = time.Now()
|
|
oldState = c.state
|
|
before = c.start
|
|
c.state = newState
|
|
c.start = now
|
|
}
|
|
|
|
c.lock.Unlock()
|
|
|
|
if now.IsZero() {
|
|
return
|
|
}
|
|
|
|
// reflect this change to slot mgr if defined (AKA hot)
|
|
if slots != nil {
|
|
slots.enterContainerState(newState)
|
|
slots.exitContainerState(oldState)
|
|
}
|
|
|
|
// update old state stats
|
|
gaugeKey := containerGaugeKeys[oldState]
|
|
if gaugeKey != "" {
|
|
stats.Record(ctx, containerGaugeMeasures[oldState].M(-1))
|
|
}
|
|
|
|
timeKey := containerTimeKeys[oldState]
|
|
if timeKey != "" {
|
|
stats.Record(ctx, containerTimeMeasures[oldState].M(int64(now.Sub(before)/time.Millisecond)))
|
|
}
|
|
|
|
// update new state stats
|
|
gaugeKey = containerGaugeKeys[newState]
|
|
if gaugeKey != "" {
|
|
stats.Record(ctx, containerGaugeMeasures[newState].M(1))
|
|
}
|
|
}
|