From fd10af5fb7f8a60f5bc3d0ebd2cbb982a029e205 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 20 May 2026 19:49:48 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix=20=E5=9C=A8=E7=BA=BF=E5=AE=9E=E9=AA=8C?= =?UTF-8?q?=EF=BC=9A=201.=20=E5=AE=9E=E9=AA=8C=E5=B7=B2=E5=88=A0=E9=99=A4?= =?UTF-8?q?=EF=BC=8CfinishExperiment=E8=BF=94=E5=9B=9E=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E8=A7=82=E5=AF=9F=E5=8F=8D=E5=A4=8D=E9=87=8D?= =?UTF-8?q?=E8=AF=95=202.=20DataSet=E5=B7=B2=E6=9C=89=E4=B8=80=E4=B8=87?= =?UTF-8?q?=E8=A1=8C=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=A4=B1=E8=B4=A5=E5=90=8E?= =?UTF-8?q?=E5=85=A8=E9=87=8F=E5=88=B7=E6=96=B0=E8=AF=84=E6=B5=8B=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../evaluation/application/experiment_app.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/backend/modules/evaluation/application/experiment_app.go b/backend/modules/evaluation/application/experiment_app.go index b4201e662..e1a44ece4 100644 --- a/backend/modules/evaluation/application/experiment_app.go +++ b/backend/modules/evaluation/application/experiment_app.go @@ -1550,11 +1550,15 @@ func (e *experimentApplication) InvokeExperiment(ctx context.Context, req *expt. if err != nil { return nil, err } - err = e.resultSvc.UpsertExptTurnResultFilter(ctx, req.GetWorkspaceID(), req.GetExperimentID(), maps.ToSlice(idMap, func(k, v int64) int64 { - return v - })) - if err != nil { - return nil, err + + // 当没有新增 item 时,跳过全量 UpsertFilter 避免无效的 O(N) CK 扫描和逐条 BMQ 发送 + if len(idMap) > 0 { + err = e.resultSvc.UpsertExptTurnResultFilter(ctx, req.GetWorkspaceID(), req.GetExperimentID(), maps.ToSlice(idMap, func(k, v int64) int64 { + return v + })) + if err != nil { + return nil, err + } } return &expt.InvokeExperimentResponse{ @@ -1570,6 +1574,10 @@ func (e *experimentApplication) FinishExperiment(ctx context.Context, req *expt. got, err := e.manager.Get(ctx, req.GetExperimentID(), req.GetWorkspaceID(), session) if err != nil { + if se, ok := errorx.FromStatusError(err); ok && se.Code() == errno.ResourceNotFoundCode { + // 实验已删除,视为已完成,幂等返回 + return &expt.FinishExperimentResponse{BaseResp: base.NewBaseResp()}, nil + } return nil, err } From faab3b971facb6d9f2121bc8bb4438da25850cdd Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 20 May 2026 19:57:31 +0800 Subject: [PATCH 2/4] fix ut --- .../application/experiment_app_test.go | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/backend/modules/evaluation/application/experiment_app_test.go b/backend/modules/evaluation/application/experiment_app_test.go index b19ba7ac4..69ecdf7c1 100644 --- a/backend/modules/evaluation/application/experiment_app_test.go +++ b/backend/modules/evaluation/application/experiment_app_test.go @@ -4338,6 +4338,45 @@ func TestExperimentApplication_InvokeExperiment(t *testing.T) { }, wantErr: false, }, + { + name: "success - empty idMap skips UpsertFilter", + req: &exptpb.InvokeExperimentRequest{ + WorkspaceID: validSpaceID, + ExperimentID: gptr.Of(validExptID), + ExperimentRunID: gptr.Of(validExptRunID), + EvaluationSetID: validEvalSetID, + Items: validItems, + Session: &common.Session{UserID: gptr.Of(validUserID)}, + SkipInvalidItems: gptr.Of(true), + AllowPartialAdd: gptr.Of(true), + }, + mockSetup: func() { + mockManager.EXPECT(). + Get(gomock.Any(), validExptID, validSpaceID, &entity.Session{UserID: strconv.FormatInt(validUserID, 10)}). + Return(validExpt, nil) + + mockAuth.EXPECT(). + AuthorizationWithoutSPI(gomock.Any(), gomock.Any()). + Return(nil) + + // BatchCreateEvaluationSetItems returns empty idMap (dataset full) + mockEvalSetItemService.EXPECT(). + BatchCreateEvaluationSetItems(gomock.Any(), gomock.Any()). + Return(map[int64]int64{}, nil, nil, nil) + + // Invoke is still called with empty Items + mockManager.EXPECT(). + Invoke(gomock.Any(), gomock.Any()). + Return(nil) + + // UpsertExptTurnResultFilter should NOT be called + }, + wantResp: &exptpb.InvokeExperimentResponse{ + AddedItems: map[int64]int64{}, + BaseResp: base.NewBaseResp(), + }, + wantErr: false, + }, { name: "error - experiment status not allowed", req: &exptpb.InvokeExperimentRequest{ @@ -4491,6 +4530,25 @@ func TestExperimentApplication_FinishExperiment(t *testing.T) { }, wantErr: false, }, + { + name: "success - experiment deleted", + req: &exptpb.FinishExperimentRequest{ + WorkspaceID: gptr.Of(validSpaceID), + ExperimentID: gptr.Of(validExptID), + ExperimentRunID: gptr.Of(validExptRunID), + Session: &common.Session{UserID: gptr.Of(validUserID)}, + }, + mockSetup: func() { + // Mock Get experiment returns ResourceNotFound (soft-deleted) + mockManager.EXPECT(). + Get(gomock.Any(), validExptID, validSpaceID, &entity.Session{UserID: strconv.FormatInt(validUserID, 10)}). + Return(nil, errorx.NewByCode(errno.ResourceNotFoundCode, errorx.WithExtraMsg("experiment not found"))) + }, + wantResp: &exptpb.FinishExperimentResponse{ + BaseResp: base.NewBaseResp(), + }, + wantErr: false, + }, { name: "error - get experiment failed", req: &exptpb.FinishExperimentRequest{ From 3259128ae1da42a45a66ae94fe62863020f062b9 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 20 May 2026 20:10:17 +0800 Subject: [PATCH 3/4] fix npe --- backend/modules/evaluation/application/eval_openapi_app.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/modules/evaluation/application/eval_openapi_app.go b/backend/modules/evaluation/application/eval_openapi_app.go index d7a6807c1..36afd0dd0 100644 --- a/backend/modules/evaluation/application/eval_openapi_app.go +++ b/backend/modules/evaluation/application/eval_openapi_app.go @@ -869,8 +869,11 @@ func (e *EvalOpenAPIApplication) ReportEvalTargetInvokeResult_(ctx context.Conte return nil, err } - logs.CtxInfo(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID()) - + if actx != nil { + logs.CtxInfo(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID()) + } else { + logs.CtxWarn(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v, invoke_id: %v, actx missing", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID(), req.GetInvokeID()) + } outputData := target.ToInvokeOutputDataDO(req) outputData.TimeConsumingMS = gptr.Of(time.Now().UnixMilli() - actx.AsyncUnixMS) if err := e.targetSvc.ReportInvokeRecords(ctx, &entity.ReportTargetRecordParam{ From 68f479f9b80b09b4978ab0d14cafb842e39aea84 Mon Sep 17 00:00:00 2001 From: xueyizheng Date: Wed, 20 May 2026 20:19:31 +0800 Subject: [PATCH 4/4] fix npe --- .../application/eval_openapi_app.go | 13 ++++++++---- .../application/eval_openapi_app_test.go | 21 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/backend/modules/evaluation/application/eval_openapi_app.go b/backend/modules/evaluation/application/eval_openapi_app.go index 36afd0dd0..136112dbd 100644 --- a/backend/modules/evaluation/application/eval_openapi_app.go +++ b/backend/modules/evaluation/application/eval_openapi_app.go @@ -869,11 +869,12 @@ func (e *EvalOpenAPIApplication) ReportEvalTargetInvokeResult_(ctx context.Conte return nil, err } - if actx != nil { - logs.CtxInfo(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID()) - } else { - logs.CtxWarn(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v, invoke_id: %v, actx missing", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID(), req.GetInvokeID()) + if actx == nil { + logs.CtxWarn(ctx, "report target record, actx missing, invoke_id: %v, space_id: %v", req.GetInvokeID(), req.GetWorkspaceID()) + return nil, errorx.New("eval async context not found, invoke_id: %v", req.GetInvokeID()) } + + logs.CtxInfo(ctx, "report target record, record_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v, item_id: %v", req.GetInvokeID(), req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID(), actx.Event.GetEvalSetItemID()) outputData := target.ToInvokeOutputDataDO(req) outputData.TimeConsumingMS = gptr.Of(time.Now().UnixMilli() - actx.AsyncUnixMS) if err := e.targetSvc.ReportInvokeRecords(ctx, &entity.ReportTargetRecordParam{ @@ -2436,6 +2437,10 @@ func (e *EvalOpenAPIApplication) ReportEvaluatorInvokeResult_(ctx context.Contex if err != nil { return nil, err } + if actx == nil { + logs.CtxWarn(ctx, "report evaluator record, actx missing, invoke_id: %v, space_id: %v", req.GetInvokeID(), req.GetWorkspaceID()) + return nil, errorx.New("eval async context not found, invoke_id: %v", req.GetInvokeID()) + } logs.CtxInfo(ctx, "report evaluator record, invoke_id: %v, evaluator_version_id: %v, space_id: %v, expt_id: %v, expt_run_id: %v", req.GetInvokeID(), actx.EvaluatorVersionID, req.GetWorkspaceID(), actx.Event.GetExptID(), actx.Event.GetExptRunID()) diff --git a/backend/modules/evaluation/application/eval_openapi_app_test.go b/backend/modules/evaluation/application/eval_openapi_app_test.go index 01dfb3f7f..9df271f39 100755 --- a/backend/modules/evaluation/application/eval_openapi_app_test.go +++ b/backend/modules/evaluation/application/eval_openapi_app_test.go @@ -1594,6 +1594,14 @@ func TestEvalOpenAPIApplication_ReportEvalTargetInvokeResult(t *testing.T) { }, wantErr: true, }, + { + name: "actx is nil", + req: repoErrorReq, + setup: func(t *testing.T, asyncRepo *repomocks.MockIEvalAsyncRepo, _ *servicemocks.MockIEvalTargetService, _ *eventmocks.MockExptEventPublisher, _ *configermocks.MockIConfiger) { + asyncRepo.EXPECT().GetEvalAsyncCtx(gomock.Any(), strconv.FormatInt(repoErrorReq.GetInvokeID(), 10)).Return(nil, nil) + }, + wantErr: true, + }, { name: "report invoke records returns error", req: reportErrorReq, @@ -5586,6 +5594,19 @@ func TestEvalOpenAPIApplication_ReportEvaluatorInvokeResult(t *testing.T) { }, wantErr: -1, }, + { + name: "actx is nil", + req: &openapi.ReportEvaluatorInvokeResultRequest{ + WorkspaceID: gptr.Of(workspaceID), + InvokeID: gptr.Of(invokeID), + Status: gptr.Of(spi.InvokeEvaluatorRunStatus_SUCCESS), + }, + setup: func(auth *rpcmocks.MockIAuthProvider, asyncRepo *repomocks.MockIEvalAsyncRepo, _ *servicemocks.MockEvaluatorService, _ *eventmocks.MockExptEventPublisher) { + auth.EXPECT().Authorization(gomock.Any(), gomock.Any()).Return(nil) + asyncRepo.EXPECT().GetEvalAsyncCtx(gomock.Any(), "evaluator:2002").Return(nil, nil) + }, + wantErr: -1, + }, { name: "report service failed", req: &openapi.ReportEvaluatorInvokeResultRequest{