mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
If naive placer is not instantiated per call/runner group (aka LBG), then the rr index will not trigger an round-robin behavior since the index is initialized and stored in the placer configuration. With this PR, moving rr index to per RunnerPool.Runners() inner loop to ensure a round robin within that set. Each time we fetch a set, since the set might be different, we reset our rr index. This means we rr within that set once, then randomly start from another node for the next RunnerPool.Runners() iteration. In busy systems, no significant behavior change is expected (accept the removal of atomic operations with respect to performance), but in idle systems round robin behavior should be more observable and simple to follow and can reduce same hit cases for the given RunnerPool.Runners(). In addition, introducing naive placer tests to ensure we observe this behavior.
64 lines
1.3 KiB
Go
64 lines
1.3 KiB
Go
package runnerpool
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/fnproject/fn/api/models"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type naivePlacer struct {
|
|
cfg PlacerConfig
|
|
}
|
|
|
|
func NewNaivePlacer(cfg *PlacerConfig) Placer {
|
|
logrus.Infof("Creating new naive runnerpool placer with config=%+v", cfg)
|
|
return &naivePlacer{
|
|
cfg: *cfg,
|
|
}
|
|
}
|
|
|
|
func (sp *naivePlacer) GetPlacerConfig() PlacerConfig {
|
|
return sp.cfg
|
|
}
|
|
|
|
func (sp *naivePlacer) PlaceCall(ctx context.Context, rp RunnerPool, call RunnerCall) error {
|
|
state := NewPlacerTracker(ctx, &sp.cfg, call)
|
|
defer state.HandleDone()
|
|
|
|
var runnerPoolErr error
|
|
for {
|
|
var runners []Runner
|
|
runners, runnerPoolErr = rp.Runners(ctx, call)
|
|
|
|
rrIndex := uint64(time.Now().Nanosecond())
|
|
|
|
for j := 0; j < len(runners) && !state.IsDone(); j++ {
|
|
|
|
rrIndex += 1
|
|
r := runners[rrIndex%uint64(len(runners))]
|
|
|
|
placed, err := state.TryRunner(r, call)
|
|
if placed {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if !state.RetryAllBackoff(len(runners), runnerPoolErr) {
|
|
break
|
|
}
|
|
}
|
|
|
|
if runnerPoolErr != nil {
|
|
// If we haven't been able to place the function and we got an error
|
|
// from the runner pool, return that error (since we don't have
|
|
// enough runners to handle the current load and the runner pool is
|
|
// having trouble).
|
|
state.HandleFindRunnersFailure(runnerPoolErr)
|
|
return runnerPoolErr
|
|
}
|
|
return models.ErrCallTimeoutServerBusy
|
|
}
|