mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Merge pull request #163 from fnproject/hot-env-changes
change hot containers when route/app vars change
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/fnproject/fn/api/runner/drivers"
|
||||
"github.com/fnproject/fn/api/runner/protocol"
|
||||
"github.com/fnproject/fn/api/runner/task"
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
@@ -62,6 +63,9 @@ type containerTask struct {
|
||||
func (t *containerTask) Command() string { return "" }
|
||||
|
||||
func (t *containerTask) EnvVars() map[string]string {
|
||||
if protocol.IsStreamable(protocol.Protocol(t.cfg.Format)) {
|
||||
return t.cfg.BaseEnv
|
||||
}
|
||||
return t.cfg.Env
|
||||
}
|
||||
func (t *containerTask) Input() io.Reader {
|
||||
@@ -82,9 +86,8 @@ func (t *containerTask) IdleTimeout() time.Duration { return t.cfg.IdleTimeo
|
||||
func (t *containerTask) Logger() (io.Writer, io.Writer) { return t.cfg.Stdout, t.cfg.Stderr }
|
||||
func (t *containerTask) Volumes() [][2]string { return [][2]string{} }
|
||||
func (t *containerTask) WorkDir() string { return "" }
|
||||
|
||||
func (t *containerTask) Close() {}
|
||||
func (t *containerTask) WriteStat(drivers.Stat) {}
|
||||
func (t *containerTask) Close() {}
|
||||
func (t *containerTask) WriteStat(drivers.Stat) {}
|
||||
|
||||
// Implementing the docker.AuthConfiguration interface. Pulling in
|
||||
// the docker repo password from environment variables
|
||||
|
||||
@@ -16,7 +16,8 @@ type Config struct {
|
||||
IdleTimeout time.Duration
|
||||
AppName string
|
||||
Memory uint64
|
||||
Env map[string]string
|
||||
BaseEnv map[string]string // only app & route config vals [for hot]
|
||||
Env map[string]string // includes BaseEnv
|
||||
Format string
|
||||
ReceivedTime time.Time
|
||||
// Ready is used to await the first pull
|
||||
|
||||
@@ -2,6 +2,7 @@ package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -132,8 +133,8 @@ func (h *htfnmgr) getPipe(ctx context.Context, rnr *Runner, cfg *task.Config) ch
|
||||
h.RLock()
|
||||
}
|
||||
|
||||
// TODO(ccirello): re-implement this without memory allocation (fmt.Sprint)
|
||||
fn := fmt.Sprint(cfg.AppName, ",", cfg.Path, cfg.Image, cfg.Timeout, cfg.Memory, cfg.Format)
|
||||
fn := key(cfg)
|
||||
|
||||
svr, ok := h.hc[fn]
|
||||
h.RUnlock()
|
||||
if !ok {
|
||||
@@ -149,6 +150,28 @@ func (h *htfnmgr) getPipe(ctx context.Context, rnr *Runner, cfg *task.Config) ch
|
||||
return svr.tasksin
|
||||
}
|
||||
|
||||
func key(cfg *task.Config) string {
|
||||
// TODO we should probably colocate this with Config, but it's kind of hot
|
||||
// specific so it makes sense here, too (just brittle & hidden)
|
||||
|
||||
// return a sha1 hash of a (hopefully) unique string of all the config
|
||||
// values, to make map lookups quicker [than the giant unique string]
|
||||
hash := sha1.New()
|
||||
fmt.Fprint(hash, cfg.AppName, "\x00")
|
||||
fmt.Fprint(hash, cfg.Path, "\x00")
|
||||
fmt.Fprint(hash, cfg.Image, "\x00")
|
||||
for k, v := range cfg.BaseEnv {
|
||||
fmt.Fprint(hash, k, "\x00", v, "\x00")
|
||||
}
|
||||
fmt.Fprint(hash, cfg.Timeout, "\x00")
|
||||
fmt.Fprint(hash, cfg.IdleTimeout, "\x00")
|
||||
fmt.Fprint(hash, cfg.Memory, "\x00")
|
||||
fmt.Fprint(hash, cfg.Format, "\x00")
|
||||
|
||||
var buf [sha1.Size]byte
|
||||
return string(hash.Sum(buf[:]))
|
||||
}
|
||||
|
||||
// htfnsvr is part of htfnmgr, abstracted apart for simplicity, its only
|
||||
// purpose is to test for hot functions saturation and try starting as many as
|
||||
// needed. In case of absence of workload, it will stop trying to start new hot
|
||||
@@ -350,7 +373,6 @@ func (hc *htfn) serve(ctx context.Context) {
|
||||
}
|
||||
}()
|
||||
|
||||
cfg.Env["FN_FORMAT"] = cfg.Format
|
||||
cfg.Timeout = 0 // add a timeout to simulate ab.end. failure.
|
||||
cfg.Stdin = hc.containerIn
|
||||
cfg.Stdout = hc.containerOut
|
||||
|
||||
@@ -142,28 +142,39 @@ func (s *Server) serve(ctx context.Context, c *gin.Context, appName string, rout
|
||||
if route.Format == "" {
|
||||
route.Format = "default"
|
||||
}
|
||||
envVars := map[string]string{
|
||||
"METHOD": c.Request.Method,
|
||||
"APP_NAME": appName,
|
||||
"ROUTE": route.Path,
|
||||
"REQUEST_URL": fmt.Sprintf("%v//%v%v", func() string {
|
||||
if c.Request.TLS == nil {
|
||||
return "http"
|
||||
}
|
||||
return "https"
|
||||
}(), c.Request.Host, c.Request.URL.String()),
|
||||
"CALL_ID": reqID,
|
||||
"FORMAT": route.Format,
|
||||
}
|
||||
|
||||
// baseVars are the vars on the route & app, not on this specific request [for hot functions]
|
||||
baseVars := make(map[string]string, len(app.Config)+len(route.Config)+3)
|
||||
baseVars["FN_FORMAT"] = route.Format
|
||||
baseVars["APP_NAME"] = appName
|
||||
baseVars["ROUTE"] = route.Path
|
||||
|
||||
// app config
|
||||
for k, v := range app.Config {
|
||||
envVars[toEnvName("", k)] = v
|
||||
k = toEnvName("", k)
|
||||
baseVars[k] = v
|
||||
}
|
||||
for k, v := range route.Config {
|
||||
envVars[toEnvName("", k)] = v
|
||||
k = toEnvName("", k)
|
||||
baseVars[k] = v
|
||||
}
|
||||
|
||||
// envVars contains the full set of env vars, per request + base
|
||||
envVars := make(map[string]string, len(baseVars)+len(params)+len(c.Request.Header)+3)
|
||||
|
||||
for k, v := range baseVars {
|
||||
envVars[k] = v
|
||||
}
|
||||
|
||||
envVars["CALL_ID"] = reqID
|
||||
envVars["METHOD"] = c.Request.Method
|
||||
envVars["REQUEST_URL"] = fmt.Sprintf("%v//%v%v", func() string {
|
||||
if c.Request.TLS == nil {
|
||||
return "http"
|
||||
}
|
||||
return "https"
|
||||
}(), c.Request.Host, c.Request.URL.String())
|
||||
|
||||
// params
|
||||
for _, param := range params {
|
||||
envVars[toEnvName("PARAM", param.Key)] = param.Value
|
||||
@@ -177,6 +188,7 @@ func (s *Server) serve(ctx context.Context, c *gin.Context, appName string, rout
|
||||
cfg := &task.Config{
|
||||
AppName: appName,
|
||||
Path: route.Path,
|
||||
BaseEnv: baseVars,
|
||||
Env: envVars,
|
||||
Format: route.Format,
|
||||
ID: reqID,
|
||||
|
||||
Reference in New Issue
Block a user