Refactor: Refine ingestion task state transitions (#16814)

### Summary

Refine ingestion task state transitions
This commit is contained in:
Jack
2026-07-10 22:47:51 +08:00
committed by GitHub
parent 9b60870fd6
commit 5e60fcec9f
27 changed files with 1425 additions and 756 deletions

View File

@@ -29,6 +29,7 @@ import (
"path/filepath"
"ragflow/internal/common"
"ragflow/internal/entity"
"ragflow/internal/httputil"
"ragflow/internal/utility"
"strconv"
"strings"
@@ -1408,7 +1409,7 @@ func (h *DocumentHandler) ListIngestionTasks(c *gin.Context) {
parseResult, err = h.documentService.ListIngestionTasks(userID, req.DatasetID, 0, 0)
if err != nil {
common.ResponseWithCodeData(c, common.CodeExceptionError, nil, err.Error())
common.ResponseWithCodeData(c, httputil.IngestionTaskErrorCode(err), nil, err.Error())
return
}
@@ -1458,7 +1459,7 @@ func (h *DocumentHandler) StopIngestionTasks(c *gin.Context) {
parseResult, err := h.documentService.StopIngestionTasks(req.Tasks, userID)
if err != nil {
common.ResponseWithCodeData(c, common.CodeExceptionError, nil, err.Error())
common.ResponseWithCodeData(c, httputil.IngestionTaskErrorCode(err), nil, err.Error())
return
}
common.SuccessWithData(c, parseResult, "success")
@@ -1484,7 +1485,7 @@ func (h *DocumentHandler) RemoveIngestionTasks(c *gin.Context) {
deletedTasks, err := h.documentService.RemoveIngestionTasks(req.Tasks, userID)
if err != nil {
common.ResponseWithCodeData(c, common.CodeExceptionError, nil, err.Error())
common.ResponseWithCodeData(c, httputil.IngestionTaskErrorCode(err), nil, err.Error())
return
}
common.SuccessWithData(c, deletedTasks, "success")

View File

@@ -38,42 +38,46 @@ import (
// fakeDocumentService implements documentServiceIface for handler tests.
type fakeDocumentService struct {
deleted int
err error
doc *service.DocumentResponse
docErr error
updateCalled bool
updatedID string
deleteCalled bool
deletedID string
stopResult map[string]interface{}
stopErr error
thumbnails map[string]string
thumbnailErr error
thumbnailUserID string
thumbnailDocIDs []string
metadataSummary map[string]interface{}
metadataErr error
metadataKBID string
metadataDocIDs []string
setMetaCalled bool
setMetaDocID string
setMetaValue map[string]interface{}
uploadLocalData []map[string]interface{}
uploadLocalErrs []string
uploadLocalKB *entity.Knowledgebase
uploadLocalPath string
uploadOverride map[string]interface{}
ingestCode common.ErrorCode
ingestErr error
ingestUserID string
ingestReq *service.IngestDocumentRequest
listOpts dao.DocumentListOptions
filterOpts dao.DocumentListOptions
filterResult map[string]interface{}
filterTotal int64
listIDs []string
metadataByKBs map[string]interface{}
deleted int
err error
doc *service.DocumentResponse
docErr error
updateCalled bool
updatedID string
deleteCalled bool
deletedID string
stopResult map[string]interface{}
stopErr error
stopIngestionTasks []*entity.IngestionTask
stopIngestionTaskErr error
removeIngestionTasks []map[string]string
removeIngestionTaskErr error
thumbnails map[string]string
thumbnailErr error
thumbnailUserID string
thumbnailDocIDs []string
metadataSummary map[string]interface{}
metadataErr error
metadataKBID string
metadataDocIDs []string
setMetaCalled bool
setMetaDocID string
setMetaValue map[string]interface{}
uploadLocalData []map[string]interface{}
uploadLocalErrs []string
uploadLocalKB *entity.Knowledgebase
uploadLocalPath string
uploadOverride map[string]interface{}
ingestCode common.ErrorCode
ingestErr error
ingestUserID string
ingestReq *service.IngestDocumentRequest
listOpts dao.DocumentListOptions
filterOpts dao.DocumentListOptions
filterResult map[string]interface{}
filterTotal int64
listIDs []string
metadataByKBs map[string]interface{}
}
func (f *fakeDocumentService) Ingest(userID string, req *service.IngestDocumentRequest) (common.ErrorCode, error) {
@@ -246,10 +250,10 @@ func (f *fakeDocumentService) IngestDocuments(datasetID, userID string, docIDs [
return nil, nil
}
func (f *fakeDocumentService) StopIngestionTasks(tasks []string, userID string) ([]*entity.IngestionTask, error) {
return nil, nil
return f.stopIngestionTasks, f.stopIngestionTaskErr
}
func (f *fakeDocumentService) RemoveIngestionTasks(tasks []string, userID string) ([]map[string]string, error) {
return nil, nil
return f.removeIngestionTasks, f.removeIngestionTaskErr
}
func setupGinContextWithUser(method, path, body string) (*gin.Context, *httptest.ResponseRecorder) {
@@ -1247,6 +1251,78 @@ func TestStopParseDocumentsHandler_NotAccessible(t *testing.T) {
}
}
func TestStopIngestionTasksHandler_InvalidTransitionReturnsConflict(t *testing.T) {
gin.SetMode(gin.TestMode)
fake := &fakeDocumentService{
stopIngestionTaskErr: &service.InvalidTaskTransitionError{TaskID: "task-1", From: common.CREATED, To: common.COMPLETED},
}
h := &DocumentHandler{documentService: fake}
c, w := setupGinContextWithUser("PUT", "/api/v1/datasets/ds-1/ingestion/tasks", `{"tasks":["task-1"]}`)
h.StopIngestionTasks(c)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
var resp map[string]interface{}
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
if resp["code"] != float64(common.CodeConflict) {
t.Fatalf("expected code %d, got %v", common.CodeConflict, resp["code"])
}
if !strings.Contains(resp["message"].(string), "task-1") {
t.Fatalf("expected task id in message, got %v", resp["message"])
}
}
func TestStopIngestionTasksHandler_TaskNotFoundReturnsNotFound(t *testing.T) {
gin.SetMode(gin.TestMode)
fake := &fakeDocumentService{
stopIngestionTaskErr: common.ErrTaskNotFound,
}
h := &DocumentHandler{documentService: fake}
c, w := setupGinContextWithUser("PUT", "/api/v1/datasets/ds-1/ingestion/tasks", `{"tasks":["task-1"]}`)
h.StopIngestionTasks(c)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
var resp map[string]interface{}
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
if resp["code"] != float64(common.CodeNotFound) {
t.Fatalf("expected code %d, got %v", common.CodeNotFound, resp["code"])
}
}
func TestRemoveIngestionTasksHandler_TaskNotFoundReturnsNotFound(t *testing.T) {
gin.SetMode(gin.TestMode)
fake := &fakeDocumentService{
removeIngestionTaskErr: common.ErrTaskNotFound,
}
h := &DocumentHandler{documentService: fake}
c, w := setupGinContextWithUser("DELETE", "/api/v1/datasets/ds-1/ingestion/tasks", `{"tasks":["task-1"]}`)
h.RemoveIngestionTasks(c)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", w.Code)
}
var resp map[string]interface{}
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
if resp["code"] != float64(common.CodeNotFound) {
t.Fatalf("expected code %d, got %v", common.CodeNotFound, resp["code"])
}
}
func TestMetadataSummaryByDataset_Success(t *testing.T) {
db := setupHandlerAccessDB(t)
orig := dao.DB