2022-05-19 13:22:37 +00:00
|
|
|
// Package api_impl implements the OpenAPI API from pkg/api/flamenco-openapi.yaml.
|
2022-01-07 16:59:30 +00:00
|
|
|
package api_impl
|
|
|
|
|
2022-03-07 14:26:46 +00:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2022-01-10 12:36:39 +00:00
|
|
|
|
2022-01-07 16:59:30 +00:00
|
|
|
import (
|
2022-07-14 15:52:38 +00:00
|
|
|
"context"
|
2022-02-14 15:53:40 +00:00
|
|
|
"fmt"
|
2022-04-08 10:02:30 +00:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
2022-05-12 09:04:05 +00:00
|
|
|
"sync"
|
2022-04-08 10:02:30 +00:00
|
|
|
"time"
|
2022-01-11 17:02:29 +00:00
|
|
|
|
2022-03-01 19:45:09 +00:00
|
|
|
"git.blender.org/flamenco/pkg/api"
|
2022-01-07 16:59:30 +00:00
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Flamenco struct {
|
2022-07-17 15:27:32 +00:00
|
|
|
jobCompiler JobCompiler
|
|
|
|
persist PersistenceService
|
|
|
|
broadcaster ChangeBroadcaster
|
|
|
|
logStorage LogStorage
|
|
|
|
config ConfigService
|
|
|
|
stateMachine TaskStateMachine
|
|
|
|
shaman Shaman
|
|
|
|
clock TimeService
|
|
|
|
lastRender LastRendered
|
|
|
|
localStorage LocalStorage
|
|
|
|
sleepScheduler WorkerSleepScheduler
|
2022-05-12 09:04:05 +00:00
|
|
|
|
|
|
|
// The task scheduler can be locked to prevent multiple Workers from getting
|
|
|
|
// the same task. It is also used for certain other queries, like
|
|
|
|
// `MayWorkerRun` to prevent similar race conditions.
|
|
|
|
taskSchedulerMutex sync.Mutex
|
2022-07-14 15:52:38 +00:00
|
|
|
|
|
|
|
// done is closed by Flamenco when it wants the application to shut down and
|
|
|
|
// restart itself from scratch.
|
|
|
|
done chan struct{}
|
2022-01-11 17:02:29 +00:00
|
|
|
}
|
|
|
|
|
2022-02-25 15:30:27 +00:00
|
|
|
var _ api.ServerInterface = (*Flamenco)(nil)
|
|
|
|
|
|
|
|
// NewFlamenco creates a new Flamenco service.
|
|
|
|
func NewFlamenco(
|
|
|
|
jc JobCompiler,
|
|
|
|
jps PersistenceService,
|
2022-04-05 14:19:33 +00:00
|
|
|
b ChangeBroadcaster,
|
2022-06-28 15:08:00 +00:00
|
|
|
logStorage LogStorage,
|
2022-02-25 15:30:27 +00:00
|
|
|
cs ConfigService,
|
|
|
|
sm TaskStateMachine,
|
2022-03-22 17:11:14 +00:00
|
|
|
sha Shaman,
|
2022-06-09 09:24:02 +00:00
|
|
|
ts TimeService,
|
2022-06-24 14:48:57 +00:00
|
|
|
lr LastRendered,
|
2022-06-28 15:08:00 +00:00
|
|
|
localStorage LocalStorage,
|
2022-07-17 15:27:32 +00:00
|
|
|
wss WorkerSleepScheduler,
|
2022-02-25 15:30:27 +00:00
|
|
|
) *Flamenco {
|
2022-01-10 16:43:30 +00:00
|
|
|
return &Flamenco{
|
2022-07-17 15:27:32 +00:00
|
|
|
jobCompiler: jc,
|
|
|
|
persist: jps,
|
|
|
|
broadcaster: b,
|
|
|
|
logStorage: logStorage,
|
|
|
|
config: cs,
|
|
|
|
stateMachine: sm,
|
|
|
|
shaman: sha,
|
|
|
|
clock: ts,
|
|
|
|
lastRender: lr,
|
|
|
|
localStorage: localStorage,
|
|
|
|
sleepScheduler: wss,
|
2022-07-14 15:52:38 +00:00
|
|
|
|
|
|
|
done: make(chan struct{}),
|
2022-01-10 16:43:30 +00:00
|
|
|
}
|
2022-01-07 16:59:30 +00:00
|
|
|
}
|
|
|
|
|
2022-07-14 15:52:38 +00:00
|
|
|
// WaitForShutdown waits until Flamenco wants to shut down the application.
|
|
|
|
// Returns `true` when the application should restart.
|
|
|
|
// Returns `false` when the context closes.
|
|
|
|
func (f *Flamenco) WaitForShutdown(ctx context.Context) bool {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return false
|
|
|
|
case <-f.done:
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// requestShutdown closes the 'done' channel, signalling to callers of
|
|
|
|
// WaitForShutdown() that a shutdown is requested.
|
|
|
|
func (f *Flamenco) requestShutdown() {
|
2022-07-14 16:22:13 +00:00
|
|
|
defer func() {
|
|
|
|
// Recover the panic that happens when the channel is closed multiple times.
|
|
|
|
// Requesting a shutdown should be possible multiple times without panicing.
|
|
|
|
recover()
|
|
|
|
}()
|
2022-07-14 15:52:38 +00:00
|
|
|
close(f.done)
|
|
|
|
}
|
|
|
|
|
2022-04-08 10:04:58 +00:00
|
|
|
// sendAPIError wraps sending of an error in the Error format, and
|
2022-01-07 16:59:30 +00:00
|
|
|
// handling the failure to marshal that.
|
2022-02-14 15:53:40 +00:00
|
|
|
func sendAPIError(e echo.Context, code int, message string, args ...interface{}) error {
|
|
|
|
if len(args) > 0 {
|
|
|
|
// Only interpret 'message' as format string if there are actually format parameters.
|
2022-05-31 09:10:49 +00:00
|
|
|
message = fmt.Sprintf(message, args...)
|
2022-02-14 15:53:40 +00:00
|
|
|
}
|
|
|
|
|
2022-04-08 10:04:58 +00:00
|
|
|
apiErr := api.Error{
|
2022-01-07 16:59:30 +00:00
|
|
|
Code: int32(code),
|
|
|
|
Message: message,
|
|
|
|
}
|
2022-04-08 10:04:58 +00:00
|
|
|
return e.JSON(code, apiErr)
|
2022-01-07 16:59:30 +00:00
|
|
|
}
|
2022-04-08 10:02:30 +00:00
|
|
|
|
|
|
|
// sendAPIErrorDBBusy sends a HTTP 503 Service Unavailable, with a hopefully
|
|
|
|
// reasonable "retry after" header.
|
|
|
|
func sendAPIErrorDBBusy(e echo.Context, message string, args ...interface{}) error {
|
|
|
|
if len(args) > 0 {
|
|
|
|
// Only interpret 'message' as format string if there are actually format parameters.
|
|
|
|
message = fmt.Sprintf(message, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
code := http.StatusServiceUnavailable
|
|
|
|
apiErr := api.Error{
|
|
|
|
Code: int32(code),
|
|
|
|
Message: message,
|
|
|
|
}
|
|
|
|
|
|
|
|
retryAfter := 1 * time.Second
|
|
|
|
seconds := int64(retryAfter.Seconds())
|
|
|
|
e.Response().Header().Set("Retry-After", strconv.FormatInt(seconds, 10))
|
|
|
|
return e.JSON(code, apiErr)
|
|
|
|
}
|