Documentation
¶
Index ¶
Constants ¶
const ( // TypeNone ... TypeNone = "" // TypeSync ... TypeSync = "sync" // TypeAsync ... TypeAsync = "async" )
const ( // FormatDefault ... FormatDefault = "default" // FormatHTTP ... FormatHTTP = "http" // FormatJSON ... FormatJSON = "json" )
const ( DefaultTimeout = 30 // seconds DefaultIdleTimeout = 30 // seconds DefaultMemory = 128 // MB MaxSyncTimeout = 120 // 2 minutes MaxAsyncTimeout = 3600 // 1 hour MaxIdleTimeout = MaxAsyncTimeout MaxMemory = 1024 * 8 // 8GB TODO should probably be a var of machine max? )
Variables ¶
var ( ErrInvalidJSON = err{ // contains filtered or unexported fields } ErrCallTimeout = err{ // contains filtered or unexported fields } ErrAppsMissingName = err{ // contains filtered or unexported fields } ErrAppsTooLongName = err{ // contains filtered or unexported fields } ErrAppsInvalidName = err{ // contains filtered or unexported fields } ErrAppsAlreadyExists = err{ // contains filtered or unexported fields } ErrAppsMissingNew = err{ // contains filtered or unexported fields } ErrAppsNameImmutable = err{ // contains filtered or unexported fields } ErrAppsNotFound = err{ // contains filtered or unexported fields } ErrDeleteAppsWithRoutes = err{ // contains filtered or unexported fields } ErrDatastoreEmptyAppName = err{ // contains filtered or unexported fields } ErrDatastoreEmptyRoutePath = err{ // contains filtered or unexported fields } ErrDatastoreEmptyApp = err{ // contains filtered or unexported fields } ErrDatastoreEmptyRoute = err{ // contains filtered or unexported fields } ErrDatastoreEmptyKey = err{ // contains filtered or unexported fields } ErrDatastoreEmptyCallID = err{ // contains filtered or unexported fields } ErrInvalidPayload = err{ // contains filtered or unexported fields } ErrRoutesAlreadyExists = err{ // contains filtered or unexported fields } ErrRoutesMissingNew = err{ // contains filtered or unexported fields } ErrRoutesNotFound = err{ // contains filtered or unexported fields } ErrRoutesPathImmutable = err{ // contains filtered or unexported fields } ErrFoundDynamicURL = err{ // contains filtered or unexported fields } ErrRoutesInvalidPath = err{ // contains filtered or unexported fields } ErrRoutesInvalidType = err{ // contains filtered or unexported fields } ErrRoutesInvalidFormat = err{ // contains filtered or unexported fields } ErrRoutesMissingAppName = err{ // contains filtered or unexported fields } ErrRoutesMissingImage = err{ // contains filtered or unexported fields } ErrRoutesMissingName = err{ // contains filtered or unexported fields } ErrRoutesMissingPath = err{ // contains filtered or unexported fields } ErrRoutesMissingType = err{ // contains filtered or unexported fields } ErrPathMalformed = err{ // contains filtered or unexported fields } ErrInvalidToTime = err{ // contains filtered or unexported fields } ErrInvalidFromTime = err{ // contains filtered or unexported fields } ErrRoutesInvalidTimeout = err{ // contains filtered or unexported fields } ErrRoutesInvalidIdleTimeout = err{ // contains filtered or unexported fields } ErrRoutesInvalidMemory = err{ // contains filtered or unexported fields } ErrCallNotFound = err{ // contains filtered or unexported fields } ErrCallLogNotFound = err{ // contains filtered or unexported fields } )
Functions ¶
This section is empty.
Types ¶
type APIError ¶
APIError any error that implements this interface will return an API response with the provided status code and error message body
func NewAPIError ¶
type App ¶
func (*App) UpdateConfig ¶
UpdateConfig adds entries from patch to a.Config, and removes entries with empty values.
type AppWrapper ¶
type AppWrapper struct {
App *App `json:"app"`
}
func (*AppWrapper) Validate ¶
func (m *AppWrapper) Validate() error
type Call ¶
type Call struct {
// Unique identifier representing a specific call.
ID string `json:"id" db:"id"`
// NOTE: this is stale, retries are not implemented atm, but this is nice, so leaving
// States and valid transitions.
//
// +---------+
// +---------> delayed <----------------+
// +----+----+ |
// | |
// | |
// +----v----+ |
// +---------> queued <----------------+
// +----+----+ *
// | *
// | retry * creates new call
// +----v----+ *
// | running | *
// +--+-+-+--+ |
// +---------|-|-|-----+-------------+
// +---|---------+ | +-----|---------+ |
// | | | | | |
// +-----v---^-+ +--v-------^+ +--v---^-+
// | success | | cancelled | | error |
// +-----------+ +-----------+ +--------+
//
// * delayed - has a delay.
// * queued - Ready to be consumed when it's turn comes.
// * running - Currently consumed by a runner which will attempt to process it.
// * success - (or complete? success/error is common javascript terminology)
// * error - Something went wrong. In this case more information can be obtained
// by inspecting the "reason" field.
// - timeout
// - killed - forcibly killed by worker due to resource restrictions or access
// violations.
// - bad_exit - exited with non-zero status due to program termination/crash.
// * cancelled - cancelled via API. More information in the reason field.
// - client_request - Request was cancelled by a client.
Status string `json:"status" db:"status"`
// App this call belongs to.
AppName string `json:"app_name" db:"app_name"`
// Path of the route that is responsible for this call
Path string `json:"path" db:"path"`
// Name of Docker image to use.
Image string `json:"image,omitempty" db:"-"`
// Number of seconds to wait before queueing the call for consumption for the
// first time. Must be a positive integer. Calls with a delay start in state
// "delayed" and transition to "running" after delay seconds.
Delay int32 `json:"delay,omitempty" db:"-"`
// Type indicates whether a task is to be run synchronously or asynchronously.
Type string `json:"type,omitempty" db:"-"`
// Format is the format to pass input into the function.
Format string `json:"format,omitempty" db:"-"`
// Payload for the call. This is only used by async calls, to store their input.
// TODO should we copy it into here too for debugging sync?
Payload string `json:"payload,omitempty" db:"-"`
// Full request url that spawned this invocation.
URL string `json:"url,omitempty" db:"-"`
// Method of the http request used to make this call.
Method string `json:"method,omitempty" db:"-"`
// Priority of the call. Higher has more priority. 3 levels from 0-2. Calls
// at same priority are processed in FIFO order.
Priority *int32 `json:"priority,omitempty" db:"-"`
// Maximum runtime in seconds.
Timeout int32 `json:"timeout,omitempty" db:"-"`
// Hot function idle timeout in seconds before termination.
IdleTimeout int32 `json:"idle_timeout,omitempty" db:"-"`
// Memory is the amount of RAM this call is allocated.
Memory uint64 `json:"memory,omitempty" db:"-"`
// BaseEnv are the env vars for hot containers, not request specific.
BaseEnv map[string]string `json:"base_env,omitempty" db:"-"`
// Env vars for the call. Comes from the ones set on the Route.
EnvVars map[string]string `json:"env_vars,omitempty" db:"-"`
// Time when call completed, whether it was successul or failed. Always in UTC.
CompletedAt strfmt.DateTime `json:"completed_at,omitempty" db:"completed_at"`
// Time when call was submitted. Always in UTC.
CreatedAt strfmt.DateTime `json:"created_at,omitempty" db:"created_at"`
// Time when call started execution. Always in UTC.
StartedAt strfmt.DateTime `json:"started_at,omitempty" db:"started_at"`
}
Call is a representation of a specific invocation of a route.
type CallFilter ¶
type Datastore ¶
type Datastore interface {
// GetApp gets an App by name.
// Returns ErrDatastoreEmptyAppName for empty appName.
// Returns ErrAppsNotFound if no app is found.
GetApp(ctx context.Context, appName string) (*App, error)
// GetApps gets a slice of Apps, optionally filtered by name.
// Missing filter or empty name will match all Apps.
GetApps(ctx context.Context, filter *AppFilter) ([]*App, error)
// InsertApp inserts an App. Returns ErrDatastoreEmptyApp when app is nil, and
// ErrDatastoreEmptyAppName when app.Name is empty.
// Returns ErrAppsAlreadyExists if an App by the same name already exists.
InsertApp(ctx context.Context, app *App) (*App, error)
// UpdateApp updates an App's Config. Returns ErrDatastoreEmptyApp when app is nil, and
// ErrDatastoreEmptyAppName when app.Name is empty.
// Returns ErrAppsNotFound if an App is not found.
UpdateApp(ctx context.Context, app *App) (*App, error)
// RemoveApp removes the App named appName. Returns ErrDatastoreEmptyAppName if appName is empty.
// Returns ErrAppsNotFound if an App is not found.
RemoveApp(ctx context.Context, appName string) error
// GetRoute looks up a matching Route for appName and the literal request route routePath.
// Returns ErrDatastoreEmptyAppName when appName is empty, and ErrDatastoreEmptyRoutePath when
// routePath is empty.
// Returns ErrRoutesNotFound when no matching route is found.
GetRoute(ctx context.Context, appName, routePath string) (*Route, error)
// GetRoutesByApp gets a slice of routes for a appName, optionally filtering on filter (filter.AppName is ignored).
// Returns ErrDatastoreEmptyAppName if appName is empty.
GetRoutesByApp(ctx context.Context, appName string, filter *RouteFilter) ([]*Route, error)
// InsertRoute inserts a route. Returns ErrDatastoreEmptyRoute when route is nil, and ErrDatastoreEmptyAppName
// or ErrDatastoreEmptyRoutePath for empty AppName or Path.
// Returns ErrRoutesAlreadyExists if the exact route.Path already exists
InsertRoute(ctx context.Context, route *Route) (*Route, error)
// UpdateRoute updates route's Config and Header fields. Returns ErrDatastoreEmptyRoute when route is nil, and
// ErrDatastoreEmptyAppName or ErrDatastoreEmptyRoutePath for empty AppName or Path.
UpdateRoute(ctx context.Context, route *Route) (*Route, error)
// RemoveRoute removes a route. Returns ErrDatastoreEmptyAppName when appName is empty, and
// ErrDatastoreEmptyRoutePath when routePath is empty. Returns ErrRoutesNotFound when no route exists.
RemoveRoute(ctx context.Context, appName, routePath string) error
// InsertCall inserts a call into the datastore, it will error if the call already
// exists.
InsertCall(ctx context.Context, call *Call) error
// GetCall returns a call at a certain id and app name.
GetCall(ctx context.Context, appName, callID string) (*Call, error)
// GetCalls returns a list of calls that satisfy the given CallFilter. If no
// calls exist, an empty list and a nil error are returned.
GetCalls(ctx context.Context, filter *CallFilter) ([]*Call, error)
// Implement LogStore methods for convenience
LogStore
// GetDatabase returns the underlying sqlx database implementation
GetDatabase() *sqlx.DB
}
type Error ¶
type Error struct {
Error *ErrorBody `json:"error,omitempty"`
}
Error uniform error output
type ErrorBody ¶
type LogStore ¶
type LogStore interface {
// InsertLog will insert the log at callID, overwriting if it previously
// existed.
InsertLog(ctx context.Context, appName, callID string, callLog io.Reader) error
// GetLog will return the log at callID, an error will be returned if the log
// cannot be found.
// TODO it would be nice if this were an io.Reader...
GetLog(ctx context.Context, appName, callID string) (*CallLog, error)
// DeleteLog will remove the log at callID, it will not return an error if
// the log does not exist before removal.
DeleteLog(ctx context.Context, appName, callID string) error
}
type MessageQueue ¶
type MessageQueue interface {
// Push a call onto the queue. If any error is returned, the call SHOULD not be
// queued. Note that this does not completely avoid double queueing, that is
// OK, a check against the datastore will be performed after a dequeue.
//
// If the job's Delay value is > 0, the job should NOT be enqueued. The job
// should only be available in the queue after at least Delay seconds have
// elapsed. No ordering is required among multiple jobs queued with similar
// delays. That is, if jobs {A, C} are queued at t seconds, both with Delay
// = 5 seconds, and the same priority, then they may be available on the
// queue as [C, A] or [A, C].
Push(context.Context, *Call) (*Call, error)
// Remove a job from the front of the queue, reserve it for a timeout and
// return it. MQ implementations MUST NOT lose jobs in case of errors. That
// is, in case of reservation failure, it should be possible to retrieve the
// job on a future reservation.
Reserve(context.Context) (*Call, error)
// If a reservation is pending, consider it acknowledged and delete it. If
// the job does not have an outstanding reservation, error. If a job did not
// exist, succeed.
Delete(context.Context, *Call) error
}
When a job is required to be restored to the queue, it should maintain it's approximate order in the queue. That is, for jobs [A, B, C], with A being the head of the queue: Reserve() leads to A being passed to a consumer, and timeout started. Next Reserve() leads to B being dequeued. This consumer finishes running the call, leading to Delete() being called. B is now permanently erased from the queue. A's timeout occurs before the job is finished. At this point the ordering should be [A, C] and not [C, A].
type Reason ¶
type Reason string
Reason Machine usable reason for job being in this state. Valid values for error status are `timeout | killed | bad_exit`. Valid values for cancelled status are `client_request`. For everything else, this is undefined.
swagger:model Reason
type Route ¶
type Route struct {
AppName string `json:"app_name" db:"app_name"`
Path string `json:"path" db:"path"`
Image string `json:"image" db:"image"`
Memory uint64 `json:"memory" db:"memory"`
Headers Headers `json:"headers" db:"headers"`
Type string `json:"type" db:"type"`
Format string `json:"format" db:"format"`
Timeout int32 `json:"timeout" db:"timeout"`
IdleTimeout int32 `json:"idle_timeout" db:"idle_timeout"`
Config Config `json:"config" db:"config"`
}
func (*Route) SetDefaults ¶
func (r *Route) SetDefaults()
SetDefaults sets zeroed field to defaults.
type RouteFilter ¶
type RouteWrapper ¶
type RouteWrapper struct {
Route *Route `json:"route"`
}
func (*RouteWrapper) Validate ¶
func (m *RouteWrapper) Validate() error