Files
fn-serverless/main.go
C Cirello 9d06b6e687 functions: common concurrency stream for sync and async (#314)
* functions: add bounded concurrency

* functions: plug runners to sync and async interfaces

* functions: update documentation about the new env var

* functions: fix test flakiness

* functions: the runner is self-regulated, no need to set a number of runners

* functions: push the execution to the background on incoming requests

* functions: ensure async tasks are always on

* functions: add prioritization to tasks consumption

Ensure that Sync tasks are consumed before Async tasks. Also, fixes
termination races problems for free.

* functions: remove stale comments

* functions: improve mem availability calculation

* functions: parallel run for async tasks

* functions: check for memory availability before pulling async task

* functions: comment about rnr.hasAvailableMemory and sync.Cond

* functions: implement memory check for async runners using Cond vars

* functions: code grooming

- remove unnecessary goroutines
- fix stale docs
- reorganize import group

* Revert "functions: implement memory check for async runners using Cond vars"

This reverts commit 922e64032201a177c03ce6a46240925e3d35430d.

* Revert "functions: comment about rnr.hasAvailableMemory and sync.Cond"

This reverts commit 49ad7d52d341f12da9603b1a1df9d145871f0e0a.

* functions: set a minimum memory availability for sync

* functions: simplify the implementation by removing the priority queue

* functions: code grooming

- code deduplication
- review waitgroups Waits
2016-11-18 18:23:26 +01:00

102 lines
2.4 KiB
Go

package main
import (
"context"
"fmt"
"os"
"os/signal"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/ccirello/supervisor"
"github.com/gin-gonic/gin"
"github.com/iron-io/functions/api/datastore"
"github.com/iron-io/functions/api/mqs"
"github.com/iron-io/functions/api/runner"
"github.com/iron-io/functions/api/server"
"github.com/spf13/viper"
)
const (
envLogLevel = "log_level"
envMQ = "mq_url"
envDB = "db_url"
envPort = "port" // be careful, Gin expects this variable to be "port"
envAPIURL = "api_url"
)
func init() {
cwd, err := os.Getwd()
if err != nil {
log.WithError(err).Fatalln("")
}
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
viper.SetDefault(envLogLevel, "info")
viper.SetDefault(envMQ, fmt.Sprintf("bolt://%s/data/worker_mq.db", cwd))
viper.SetDefault(envDB, fmt.Sprintf("bolt://%s/data/bolt.db?bucket=funcs", cwd))
viper.SetDefault(envPort, 8080)
viper.SetDefault(envAPIURL, fmt.Sprintf("http://127.0.0.1:%d", viper.GetInt(envPort)))
viper.AutomaticEnv() // picks up env vars automatically
logLevel, err := log.ParseLevel(viper.GetString("log_level"))
if err != nil {
log.WithError(err).Fatalln("Invalid log level.")
}
log.SetLevel(logLevel)
gin.SetMode(gin.ReleaseMode)
if logLevel == log.DebugLevel {
gin.SetMode(gin.DebugMode)
}
}
func main() {
ctx, halt := context.WithCancel(context.Background())
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
log.Info("Halting...")
halt()
}()
ds, err := datastore.New(viper.GetString(envDB))
if err != nil {
log.WithError(err).Fatalln("Invalid DB url.")
}
mqType, err := mqs.New(viper.GetString(envMQ))
if err != nil {
log.WithError(err).Fatal("Error on init MQ")
}
metricLogger := runner.NewMetricLogger()
rnr, err := runner.New(metricLogger)
if err != nil {
log.WithError(err).Fatalln("Failed to create a runner")
}
svr := &supervisor.Supervisor{
Log: func(msg interface{}) {
log.Debug("supervisor: ", msg)
},
}
tasks := make(chan runner.TaskRequest)
svr.AddFunc(func(ctx context.Context) {
runner.StartWorkers(ctx, rnr, tasks)
})
svr.AddFunc(func(ctx context.Context) {
srv := server.New(ds, mqType, rnr, tasks)
srv.Run(ctx)
})
apiURL := viper.GetString(envAPIURL)
svr.AddFunc(func(ctx context.Context) {
runner.RunAsyncRunner(ctx, apiURL, tasks, rnr)
})
svr.Serve(ctx)
close(tasks)
}