diff --git a/backend/application/app/app.go b/backend/application/app/app.go index d0e76efd..5d2ee215 100644 --- a/backend/application/app/app.go +++ b/backend/application/app/app.go @@ -60,6 +60,7 @@ import ( "github.com/coze-dev/coze-studio/backend/pkg/lang/conv" "github.com/coze-dev/coze-studio/backend/pkg/lang/ptr" "github.com/coze-dev/coze-studio/backend/pkg/logs" + "github.com/coze-dev/coze-studio/backend/pkg/safego" "github.com/coze-dev/coze-studio/backend/pkg/taskgroup" "github.com/coze-dev/coze-studio/backend/types/consts" "github.com/coze-dev/coze-studio/backend/types/errno" @@ -183,18 +184,19 @@ func (a *APPApplicationService) DraftProjectDelete(ctx context.Context, req *pro logs.CtxErrorf(ctx, "publish project '%d' failed, err=%v", req.ProjectID, err) } - err = a.deleteAPPResources(ctx, req.ProjectID) - if err != nil { - logs.CtxErrorf(ctx, "delete app '%d' resources failed, err=%v", req.ProjectID, err) - } + safego.Go(ctx, func() { + // When an app is deleted, resource deletion is currently handled as a weak dependency, meaning some resources might not be deleted, but they will be inaccessible to the user. + // TODO:: Application resources need to check the deletion status of the application + a.deleteAPPResources(ctx, req.ProjectID) + }) resp = &projectAPI.DraftProjectDeleteResponse{} return resp, nil } -func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID int64) (err error) { - err = plugin.PluginApplicationSVC.DeleteAPPAllPlugins(ctx, appID) +func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID int64) { + err := plugin.PluginApplicationSVC.DeleteAPPAllPlugins(ctx, appID) if err != nil { logs.CtxErrorf(ctx, "delete app '%d' plugins failed, err=%v", appID, err) } @@ -218,8 +220,6 @@ func (a *APPApplicationService) deleteAPPResources(ctx context.Context, appID in if err != nil { logs.CtxErrorf(ctx, "delete app '%d' workflow failed, err=%v", appID, err) } - - return nil } func (a *APPApplicationService) DraftProjectUpdate(ctx context.Context, req *projectAPI.DraftProjectUpdateRequest) (resp *projectAPI.DraftProjectUpdateResponse, err error) { diff --git a/backend/application/plugin/init.go b/backend/application/plugin/init.go index c11ab02d..ecf433af 100644 --- a/backend/application/plugin/init.go +++ b/backend/application/plugin/init.go @@ -18,9 +18,12 @@ package plugin import ( "context" + "strconv" + "strings" "gorm.io/gorm" + "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" "github.com/coze-dev/coze-studio/backend/domain/plugin/repository" "github.com/coze-dev/coze-studio/backend/domain/plugin/service" @@ -28,6 +31,9 @@ import ( user "github.com/coze-dev/coze-studio/backend/domain/user/service" "github.com/coze-dev/coze-studio/backend/infra/contract/idgen" "github.com/coze-dev/coze-studio/backend/infra/contract/storage" + "github.com/coze-dev/coze-studio/backend/pkg/errorx" + "github.com/coze-dev/coze-studio/backend/pkg/lang/slices" + "github.com/coze-dev/coze-studio/backend/types/errno" ) type ServiceComponents struct { @@ -68,6 +74,11 @@ func InitService(ctx context.Context, components *ServiceComponents) (*PluginApp OAuthRepo: oauthRepo, }) + err = checkIDExist(ctx, pluginSVC) + if err != nil { + return nil, err + } + PluginApplicationSVC.DomainSVC = pluginSVC PluginApplicationSVC.eventbus = components.EventBus PluginApplicationSVC.oss = components.OSS @@ -77,3 +88,51 @@ func InitService(ctx context.Context, components *ServiceComponents) (*PluginApp return PluginApplicationSVC, nil } + +func checkIDExist(ctx context.Context, pluginService service.PluginService) error { + pluginProducts := conf.GetAllPluginProducts() + + pluginIDs := make([]int64, 0, len(pluginProducts)) + var toolIDs []int64 + for _, p := range pluginProducts { + pluginIDs = append(pluginIDs, p.Info.ID) + toolIDs = append(toolIDs, p.ToolIDs...) + } + + pluginInfos, err := pluginService.MGetDraftPlugins(ctx, pluginIDs) + if err != nil { + return err + } + if len(pluginInfos) > 0 { + conflictsIDs := make([]int64, 0, len(pluginInfos)) + for _, p := range pluginInfos { + conflictsIDs = append(conflictsIDs, p.ID) + } + + return errorx.New(errno.ErrPluginIDExist, + errorx.KV("plugin_id", strings.Join(slices.Transform(conflictsIDs, func(id int64) string { + return strconv.FormatInt(id, 10) + }), ",")), + ) + } + + tools, err := pluginService.MGetDraftTools(ctx, toolIDs) + if err != nil { + return err + } + + if len(tools) > 0 { + conflictsIDs := make([]int64, 0, len(tools)) + for _, t := range tools { + conflictsIDs = append(conflictsIDs, t.ID) + } + + return errorx.New(errno.ErrToolIDExist, + errorx.KV("tool_id", strings.Join(slices.Transform(conflictsIDs, func(id int64) string { + return strconv.FormatInt(id, 10) + }), ",")), + ) + } + return nil + +} diff --git a/backend/domain/plugin/internal/dal/plugin_draft.go b/backend/domain/plugin/internal/dal/plugin_draft.go index 612ba1a1..53ad06ab 100644 --- a/backend/domain/plugin/internal/dal/plugin_draft.go +++ b/backend/domain/plugin/internal/dal/plugin_draft.go @@ -27,6 +27,7 @@ import ( "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common" + "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" "github.com/coze-dev/coze-studio/backend/domain/plugin/entity" "github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model" "github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query" @@ -88,7 +89,7 @@ func (p *PluginDraftDAO) getSelected(opt *PluginSelectedOption) (selected []fiel } func (p *PluginDraftDAO) Create(ctx context.Context, plugin *entity.PluginInfo) (pluginID int64, err error) { - id, err := p.idGen.GenID(ctx) + id, err := p.genPluginID(ctx) if err != nil { return 0, err } @@ -117,6 +118,25 @@ func (p *PluginDraftDAO) Create(ctx context.Context, plugin *entity.PluginInfo) return id, nil } +func (p *PluginDraftDAO) genPluginID(ctx context.Context) (id int64, err error) { + + retryTimes := 5 + for i := 0; i < retryTimes; i++ { + id, err = p.idGen.GenID(ctx) + if err != nil { + return 0, err + } + if _, ok := conf.GetPluginProduct(id); !ok { + break + } + if i == retryTimes-1 { + return 0, fmt.Errorf("id %d is confilict with product plugin id.", id) + } + } + + return id, nil +} + func (p *PluginDraftDAO) Get(ctx context.Context, pluginID int64, opt *PluginSelectedOption) (plugin *entity.PluginInfo, exist bool, err error) { table := p.query.PluginDraft pl, err := table.WithContext(ctx). @@ -262,7 +282,7 @@ func (p *PluginDraftDAO) Update(ctx context.Context, plugin *entity.PluginInfo) } func (p *PluginDraftDAO) CreateWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (pluginID int64, err error) { - id, err := p.idGen.GenID(ctx) + id, err := p.genPluginID(ctx) if err != nil { return 0, err } diff --git a/backend/domain/plugin/internal/dal/tool_draft.go b/backend/domain/plugin/internal/dal/tool_draft.go index 0679d319..a7bbd737 100644 --- a/backend/domain/plugin/internal/dal/tool_draft.go +++ b/backend/domain/plugin/internal/dal/tool_draft.go @@ -27,6 +27,7 @@ import ( "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin" common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common" + "github.com/coze-dev/coze-studio/backend/domain/plugin/conf" "github.com/coze-dev/coze-studio/backend/domain/plugin/entity" "github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model" "github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query" @@ -90,7 +91,8 @@ func (t *ToolDraftDAO) getSelected(opt *ToolSelectedOption) (selected []field.Ex } func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolID int64, err error) { - id, err := t.idGen.GenID(ctx) + + id, err := t.genToolID(ctx) if err != nil { return 0, err } @@ -111,6 +113,27 @@ func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolI return id, nil } +func (t *ToolDraftDAO) genToolID(ctx context.Context) (id int64, err error) { + + retryTimes := 5 + + for i := 0; i < retryTimes; i++ { + id, err = t.idGen.GenID(ctx) + if err != nil { + return 0, err + } + + if _, ok := conf.GetToolProduct(id); !ok { + break + } + if i == retryTimes-1 { + return 0, fmt.Errorf("id %d is confilict with product tool id.", id) + } + } + + return id, nil +} + func (t *ToolDraftDAO) Get(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) { table := t.query.ToolDraft tl, err := table.WithContext(ctx). @@ -335,7 +358,7 @@ func (t *ToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, tls := make([]*model.ToolDraft, 0, len(tools)) for _, tool := range tools { - id, err := t.idGen.GenID(ctx) + id, err := t.genToolID(ctx) if err != nil { return nil, err } diff --git a/backend/types/errno/plugin.go b/backend/types/errno/plugin.go index db3cd432..f9edb70b 100644 --- a/backend/types/errno/plugin.go +++ b/backend/types/errno/plugin.go @@ -38,6 +38,8 @@ const ( ErrPluginToolsCheckFailed = 109000011 ErrPluginParseToolRespFailed = 109000012 ErrPluginOAuthFailed = 109000013 + ErrPluginIDExist = 109000014 + ErrToolIDExist = 109000015 ) const ( @@ -45,6 +47,17 @@ const ( ) func init() { + + code.Register( + ErrPluginIDExist, + "Plugin ID already exists : {plugin_id}", + code.WithAffectStability(false), + ) + code.Register( + ErrToolIDExist, + "Tool ID already exists : {tool_id}", + code.WithAffectStability(false), + ) code.Register( ErrPluginPermissionCode, fmt.Sprintf("unauthorized access : {%s}", PluginMsgKey),