mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Hybrid plumby (#585)
* fix configuration of agent and server to be future proof and plumb in the hybrid client agent * fixes up the tests, turns off /r/ on api nodes * fix up defaults for runner nodes * shove the runner async push code down into agent land to use client * plumb up async-age * return full call from async dequeue endpoint, since we're storing a whole call in the MQ we don't need to worry about caching of app/route [for now] * fast safe shutdown of dequeue looper in runner / tidying of agent * nice errors for path not found against /r/, /v1/ or other path not found * removed some stale TODO in agent * mq backends are only loud mouths in debug mode now * update tests * Add caching to hybrid client * Fix HTTP error handling in hybrid client. The type switch was on the value rather than a pointer. * Gofmt. * Better caching with a nice caching wrapper * Remove datastore cache which is now unused * Don't need to manually wrap interface methods * Go fmt
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/fnproject/fn/api/common"
|
||||
"github.com/fnproject/fn/api/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
func (s *Server) handleRunnerEnqueue(c *gin.Context) {
|
||||
@@ -40,11 +39,12 @@ func (s *Server) handleRunnerEnqueue(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO once update call is hooked up, do this
|
||||
// at this point, the message is on the queue and could be picked up by a
|
||||
// runner and enter into 'running' state before we can insert it in the db as
|
||||
// 'queued' state. we can ignore any error inserting into db here and Start
|
||||
// will ensure the call exists in the db in 'running' state there.
|
||||
s.Datastore.InsertCall(ctx, &call)
|
||||
// s.Datastore.InsertCall(ctx, &call)
|
||||
|
||||
c.JSON(200, struct {
|
||||
M string `json:"msg"`
|
||||
@@ -55,25 +55,23 @@ func (s *Server) handleRunnerDequeue(c *gin.Context) {
|
||||
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// TODO finalize (return whole call?) and move
|
||||
type m struct {
|
||||
AppName string `json:"app_name"`
|
||||
Path string `json:"path"`
|
||||
}
|
||||
type resp struct {
|
||||
M []m `json:"calls"`
|
||||
var resp struct {
|
||||
M []*models.Call `json:"calls"`
|
||||
}
|
||||
var m [1]*models.Call // avoid alloc
|
||||
resp.M = m[:0]
|
||||
|
||||
// long poll until ctx expires / we find a message
|
||||
var b common.Backoff
|
||||
for {
|
||||
msg, err := s.MQ.Reserve(ctx)
|
||||
call, err := s.MQ.Reserve(ctx)
|
||||
if err != nil {
|
||||
handleErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
if msg != nil {
|
||||
c.JSON(200, resp{M: []m{{AppName: msg.AppName, Path: msg.Path}}})
|
||||
if call != nil {
|
||||
resp.M = append(resp.M, call)
|
||||
c.JSON(200, resp)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -81,26 +79,25 @@ func (s *Server) handleRunnerDequeue(c *gin.Context) {
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.JSON(200, resp{M: make([]m, 0)})
|
||||
c.JSON(200, resp) // TODO assert this return `[]` & not 'nil'
|
||||
return
|
||||
default:
|
||||
default: // poll until we find a cookie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleRunnerStart(c *gin.Context) {
|
||||
var body struct {
|
||||
AppName string `json:"app_name"`
|
||||
CallID string `json:"id"`
|
||||
}
|
||||
ctx := c.Request.Context()
|
||||
|
||||
// TODO just take a whole call here? maybe the runner wants to mark it as error?
|
||||
err := c.BindJSON(&body)
|
||||
var call models.Call
|
||||
err := c.BindJSON(&call)
|
||||
if err != nil {
|
||||
handleErrorResponse(c, models.ErrInvalidJSON)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO validate call?
|
||||
|
||||
// TODO hook up update. we really just want it to set status to running iff
|
||||
// status=queued, but this must be in a txn in Update with behavior:
|
||||
// queued->running
|
||||
@@ -112,21 +109,21 @@ func (s *Server) handleRunnerStart(c *gin.Context) {
|
||||
// there is nuance for running->error as in theory it could be the correct machine retrying
|
||||
// and we risk not running a task [ever]. needs further thought, but marking as error will
|
||||
// cover our tracks since if the db is down we can't run anything anyway (treat as such).
|
||||
var call models.Call
|
||||
call.AppName = body.AppName
|
||||
call.ID = body.CallID
|
||||
call.Status = "running"
|
||||
call.StartedAt = strfmt.DateTime(time.Now())
|
||||
// TODO do this client side and validate it here?
|
||||
//call.Status = "running"
|
||||
//call.StartedAt = strfmt.DateTime(time.Now())
|
||||
//err := s.Datastore.UpdateCall(c.Request.Context(), &call)
|
||||
//if err != nil {
|
||||
//if err == InvalidStatusChange {
|
||||
//// TODO we could either let UpdateCall handle setting to error or do it
|
||||
//// here explicitly
|
||||
|
||||
//if err := s.MQ.Delete(&call); err != nil { // TODO change this to take some string(s), not a whole call
|
||||
//logrus.WithFields(logrus.Fields{"id": call.Id}).WithError(err).Error("error deleting mq message")
|
||||
//// just log this one, return error from update call
|
||||
//}
|
||||
// TODO change this to only delete message if the status change fails b/c it already ran
|
||||
// after messaging semantics change
|
||||
if err := s.MQ.Delete(ctx, &call); err != nil { // TODO change this to take some string(s), not a whole call
|
||||
handleErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
//}
|
||||
//handleErrorResponse(c, err)
|
||||
//return
|
||||
@@ -166,13 +163,14 @@ func (s *Server) handleRunnerFinish(c *gin.Context) {
|
||||
// note: Not returning err here since the job could have already finished successfully.
|
||||
}
|
||||
|
||||
// TODO open this up after we change messaging semantics.
|
||||
// TODO we don't know whether a call is async or sync. we likely need an additional
|
||||
// arg in params for a message id and can detect based on this. for now, delete messages
|
||||
// for sync and async even though sync doesn't have any (ignore error)
|
||||
if err := s.MQ.Delete(ctx, &call); err != nil { // TODO change this to take some string(s), not a whole call
|
||||
common.Logger(ctx).WithError(err).Error("error deleting mq msg")
|
||||
// note: Not returning err here since the job could have already finished successfully.
|
||||
}
|
||||
//if err := s.MQ.Delete(ctx, &call); err != nil { // TODO change this to take some string(s), not a whole call
|
||||
//common.Logger(ctx).WithError(err).Error("error deleting mq msg")
|
||||
//// note: Not returning err here since the job could have already finished successfully.
|
||||
//}
|
||||
|
||||
c.JSON(200, struct {
|
||||
M string `json:"msg"`
|
||||
|
||||
Reference in New Issue
Block a user