Fix error fetching non-existing log tail
A task can exist in the database but not have any log stored on disk yet. This is now returned as `204 No Content` instead of an internal server error. The web interface is also adjusted to cope with this.
This commit is contained in:
parent
a3d885e710
commit
ce07a46455
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
@ -197,13 +198,23 @@ func (f *Flamenco) FetchTaskLogTail(e echo.Context, taskID string) error {
|
|||||||
logger.Error().Err(err).Msg("error fetching task")
|
logger.Error().Err(err).Msg("error fetching task")
|
||||||
return sendAPIError(e, http.StatusInternalServerError, "error fetching task: %v", err)
|
return sendAPIError(e, http.StatusInternalServerError, "error fetching task: %v", err)
|
||||||
}
|
}
|
||||||
|
logger = logger.With().Str("job", dbTask.Job.UUID).Logger()
|
||||||
|
|
||||||
tail, err := f.logStorage.Tail(dbTask.Job.UUID, taskID)
|
tail, err := f.logStorage.Tail(dbTask.Job.UUID, taskID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
logger.Debug().Msg("task tail unavailable, task has no log on disk")
|
||||||
|
return e.NoContent(http.StatusNoContent)
|
||||||
|
}
|
||||||
logger.Error().Err(err).Msg("unable to fetch task log tail")
|
logger.Error().Err(err).Msg("unable to fetch task log tail")
|
||||||
return sendAPIError(e, http.StatusInternalServerError, "error fetching task log tail: %v", err)
|
return sendAPIError(e, http.StatusInternalServerError, "error fetching task log tail: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tail == "" {
|
||||||
|
logger.Debug().Msg("task tail unavailable, on-disk task log is empty")
|
||||||
|
return e.NoContent(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Debug().Msg("fetched task tail")
|
logger.Debug().Msg("fetched task tail")
|
||||||
return e.String(http.StatusOK, tail)
|
return e.String(http.StatusOK, tail)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ package api_impl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -187,3 +189,46 @@ func TestSetJobStatus_happy(t *testing.T) {
|
|||||||
|
|
||||||
assertResponseEmpty(t, echoCtx)
|
assertResponseEmpty(t, echoCtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFetchTaskLogTail(t *testing.T) {
|
||||||
|
mockCtrl := gomock.NewController(t)
|
||||||
|
defer mockCtrl.Finish()
|
||||||
|
|
||||||
|
mf := newMockedFlamenco(mockCtrl)
|
||||||
|
|
||||||
|
jobID := "18a9b096-d77e-438c-9be2-74397038298b"
|
||||||
|
taskID := "2e020eee-20f8-4e95-8dcf-65f7dfc3ebab"
|
||||||
|
dbJob := persistence.Job{
|
||||||
|
UUID: jobID,
|
||||||
|
Name: "test job",
|
||||||
|
Status: api.JobStatusActive,
|
||||||
|
Settings: persistence.StringInterfaceMap{},
|
||||||
|
Metadata: persistence.StringStringMap{},
|
||||||
|
}
|
||||||
|
dbTask := persistence.Task{
|
||||||
|
UUID: taskID,
|
||||||
|
Job: &dbJob,
|
||||||
|
Name: "test task",
|
||||||
|
}
|
||||||
|
|
||||||
|
// The task can be found, but has no on-disk task log.
|
||||||
|
// This should not cause any error, but instead be returned as "no content".
|
||||||
|
mf.persistence.EXPECT().FetchTask(gomock.Any(), taskID).Return(&dbTask, nil)
|
||||||
|
mf.logStorage.EXPECT().Tail(jobID, taskID).
|
||||||
|
Return("", fmt.Errorf("wrapped error: %w", os.ErrNotExist))
|
||||||
|
|
||||||
|
echoCtx := mf.prepareMockedRequest(nil)
|
||||||
|
err := mf.flamenco.FetchTaskLogTail(echoCtx, taskID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assertResponseEmpty(t, echoCtx)
|
||||||
|
|
||||||
|
// Check that a 204 No Content is also returned when the task log file on disk exists, but is empty.
|
||||||
|
mf.persistence.EXPECT().FetchTask(gomock.Any(), taskID).Return(&dbTask, nil)
|
||||||
|
mf.logStorage.EXPECT().Tail(jobID, taskID).
|
||||||
|
Return("", fmt.Errorf("wrapped error: %w", os.ErrNotExist))
|
||||||
|
|
||||||
|
echoCtx = mf.prepareMockedRequest(nil)
|
||||||
|
err = mf.flamenco.FetchTaskLogTail(echoCtx, taskID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assertResponseEmpty(t, echoCtx)
|
||||||
|
}
|
||||||
|
@ -84,9 +84,13 @@ func TestLogTail(t *testing.T) {
|
|||||||
jobID := "25c5a51c-e0dd-44f7-9f87-74f3d1fbbd8c"
|
jobID := "25c5a51c-e0dd-44f7-9f87-74f3d1fbbd8c"
|
||||||
taskID := "20ff9d06-53ec-4019-9e2e-1774f05f170a"
|
taskID := "20ff9d06-53ec-4019-9e2e-1774f05f170a"
|
||||||
|
|
||||||
err := s.Write(zerolog.Nop(), jobID, taskID, "Just a single line")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
contents, err := s.Tail(jobID, taskID)
|
contents, err := s.Tail(jobID, taskID)
|
||||||
|
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||||
|
assert.Equal(t, "", contents)
|
||||||
|
|
||||||
|
err = s.Write(zerolog.Nop(), jobID, taskID, "Just a single line")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
contents, err = s.Tail(jobID, taskID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "Just a single line\n", string(contents))
|
assert.Equal(t, "Just a single line\n", string(contents))
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ export const useTaskLog = defineStore('taskLog', {
|
|||||||
* @param {string} logChunk
|
* @param {string} logChunk
|
||||||
*/
|
*/
|
||||||
addChunk(logChunk) {
|
addChunk(logChunk) {
|
||||||
|
if (!logChunk) return;
|
||||||
|
|
||||||
const lines = logChunk.trimEnd().split('\n');
|
const lines = logChunk.trimEnd().split('\n');
|
||||||
if (lines.length == 0)
|
if (lines.length == 0)
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user