5. 數據訪問層
5.1 倉儲接口定義
插件倉儲接口
文件位置:backend/domain/plugin/repository/plugin.go
type PluginRepository interface {// DeleteDraftPlugin 刪除插件草稿DeleteDraftPlugin(ctx context.Context, pluginID int64) error// DeleteAPPAllPlugins 刪除應用下所有插件DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error)// GetDraftPlugin 獲取插件草稿GetDraftPlugin(ctx context.Context, pluginID int64, opt *dal.PluginSelectedOption) (*entity.PluginInfo, error)// 其他CRUD方法...
}
刪除方法特點:
- 事務刪除:DeleteDraftPlugin方法支持事務操作,確保數據一致性
- 批量刪除:DeleteAPPAllPlugins支持批量刪除應用下的所有插件
- 上下文支持:支持context.Context進行請求鏈路追蹤
- 錯誤處理:返回error類型,便于上層進行錯誤處理
- ID定位:通過唯一pluginID精確定位要刪除的插件資源
5.2 數據訪問對象(DAO)
插件刪除的具體實現
文件位置:backend/domain/plugin/repository/plugin_impl.go
插件刪除操作涉及多個數據表的級聯刪除,需要通過事務確保數據一致性:
func (p *pluginRepoImpl) DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error) {tx := p.query.Begin()if tx.Error != nil {return tx.Error}defer func() {if r := recover(); r != nil {if e := tx.Rollback(); e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))return}if err != nil {if e := tx.Rollback(); e != nil {logs.CtxErrorf(ctx, "rollback failed, err=%v", e)}}}()// 刪除插件草稿數據err = p.pluginDraftDAO.DeleteWithTX(ctx, tx, pluginID)if err != nil {return err}// 刪除插件基礎數據err = p.pluginDAO.DeleteWithTX(ctx, tx, pluginID)if err != nil {return err}// 刪除插件版本數據err = p.pluginVersionDAO.DeleteWithTX(ctx, tx, pluginID)if err != nil {return err}// 刪除插件下的所有工具草稿err = p.toolDraftDAO.DeleteAllWithTX(ctx, tx, pluginID)if err != nil {return err}// 刪除插件下的所有工具數據err = p.toolDAO.DeleteAllWithTX(ctx, tx, pluginID)if err != nil {return err}// 刪除工具版本數據err = p.toolVersionDAO.DeleteWithTX(ctx, tx, pluginID)if err != nil {return err}return tx.Commit()
}
刪除操作的關鍵特點:
- 事務保證:使用數據庫事務確保所有刪除操作的原子性
- 級聯刪除:刪除插件時同時刪除相關的工具、版本等數據
- 異常處理:完善的panic恢復和事務回滾機制
- 數據完整性:確保刪除操作不會留下孤立的數據記錄
- 多表協調:協調刪除插件相關的多個數據表
刪除涉及的數據表:
- plugin_draft:插件草稿表
- plugin:插件基礎信息表
- plugin_version:插件版本表
- tool_draft:工具草稿表
- tool:工具信息表
- tool_version:工具版本表
PluginDraftDAO結構體
文件位置:backend/domain/plugin/internal/dal/plugin_draft.go
PluginDraftDAO是插件草稿數據訪問的具體實現,負責與數據庫進行交互,處理插件草稿資源的持久化操作。
package dalimport ("context""encoding/json""fmt""gorm.io/gen""gorm.io/gorm""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""github.com/coze-dev/coze-studio/backend/infra/contract/idgen""github.com/coze-dev/coze-studio/backend/pkg/slices"
)type PluginDraftDAO struct {query *query.QueryidGen idgen.IDGenerator
}func NewPluginDraftDAO(db *gorm.DB, generator idgen.IDGenerator) *PluginDraftDAO {return &PluginDraftDAO{query: query.Use(db),idGen: generator,}
}
插件刪除操作實現
刪除插件草稿:
func (p *PluginDraftDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {table := tx.PluginDraft_, err = table.WithContext(ctx).Where(table.ID.Eq(pluginID)).Delete()if err != nil {return err}return nil
}
ToolDraftDAO刪除操作
文件位置:backend/domain/plugin/internal/dal/tool_draft.go
批量刪除工具草稿:
func (t *ToolDraftDAO) DeleteAllWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {const limit = 20table := tx.ToolDraftfor {info, err := table.WithContext(ctx).Where(table.PluginID.Eq(pluginID)).Limit(limit).Delete()if err != nil {return err}if info.RowsAffected < limit {break}}return nil
}
數據轉換方法
DO到PO轉換(Domain Object to Persistent Object):
func (p *PluginDraftDAO) pluginInfoDO2PO(plugin *entity.PluginInfo) *model.PluginDraft {mf, _ := plugin.Manifest.EncryptAuthPayload()return &model.PluginDraft{ID: plugin.ID,SpaceID: plugin.SpaceID,DeveloperID: plugin.DeveloperID,PluginType: int32(plugin.PluginType),IconURI: plugin.GetIconURI(),ServerURL: plugin.GetServerURL(),AppID: plugin.GetAPPID(),Manifest: mf,OpenapiDoc: plugin.OpenapiDoc,}
}
PO到DO轉換(Persistent Object to Domain Object):
type pluginDraftPO model.PluginDraftfunc (p pluginDraftPO) ToDO() *entity.PluginInfo {plugin := &entity.PluginInfo{ID: p.ID,SpaceID: p.SpaceID,DeveloperID: p.DeveloperID,PluginType: common.PluginType(p.PluginType),IconURI: &p.IconURI,ServerURL: &p.ServerURL,APPID: &p.AppID,Manifest: p.Manifest,OpenapiDoc: p.OpenapiDoc,CreatedAt: p.CreatedAt,UpdatedAt: p.UpdatedAt,}return plugin
}
刪除操作特點:
- 事務刪除:DeleteWithTX方法支持事務操作,確保數據一致性
- 精確定位:通過pluginID精確定位要刪除的插件資源
- 條件構建:使用GORM Gen生成的類型安全查詢條件
- 物理刪除:執行物理刪除操作,從數據庫中徹底移除記錄
- 批量刪除:ToolDraftDAO支持批量刪除插件下的所有工具
- 分頁刪除:使用limit分頁刪除,避免大量數據刪除時的性能問題
刪除插件的完整數據訪問流程:
在刪除插件的場景中,數據訪問層的操作流程如下:
- 刪除前驗證:調用GetDraftPlugin方法獲取插件信息,驗證資源存在性
- 權限檢查:在應用層驗證當前用戶是否為插件開發者
- 事務開始:開啟數據庫事務,確保刪除操作的原子性
- 級聯刪除:依次刪除插件草稿、插件基礎數據、版本數據、工具數據等
- 事務提交:所有刪除操作成功后提交事務
- 錯誤回滾:任何刪除操作失敗時回滾事務,保證數據一致性
這種設計確保了刪除操作的安全性、可靠性和數據完整性。
數據訪問層刪除操作總結:
刪除插件在數據訪問層的實現具有以下特點:
- 事務保證:所有刪除操作在事務中執行,確保數據一致性
- 級聯刪除:自動刪除插件相關的所有數據,包括工具、版本等
- 類型安全:使用GORM Gen生成的類型安全查詢條件,避免SQL注入風險
- 錯誤處理:完善的錯誤處理和事務回滾機制
- 物理刪除:執行真正的物理刪除操作,徹底從數據庫中移除記錄
- 性能優化:通過分頁刪除和精確的WHERE條件,確保刪除操作的高效執行
5.3 插件數據模型
PluginDraft數據模型
文件位置:backend/domain/plugin/internal/dal/model/plugin_draft.gen.go
該文件由GORM代碼生成工具自動生成,定義了與數據庫表對應的Go結構體。在刪除插件操作中,該模型定義了數據庫記錄的結構,為刪除操作提供了數據映射基礎。
// Code generated by gorm.io/gen. DO NOT EDIT.
package modelconst TableNamePluginDraft = "plugin_draft"// PluginDraft plugin_draft
type PluginDraft struct {ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:id" json:"id"` // idSpaceID int64 `gorm:"column:space_id;not null;comment:space id" json:"space_id"` // space idDeveloperID int64 `gorm:"column:developer_id;not null;comment:developer id" json:"developer_id"` // developer idPluginType int32 `gorm:"column:plugin_type;not null;comment:plugin type" json:"plugin_type"` // plugin typeIconURI string `gorm:"column:icon_uri;comment:icon uri" json:"icon_uri"` // icon uriServerURL string `gorm:"column:server_url;comment:server url" json:"server_url"` // server urlAppID int64 `gorm:"column:app_id;comment:app id" json:"app_id"` // app idManifest *PluginManifest `gorm:"column:manifest;comment:plugin manifest" json:"manifest"` // plugin manifestOpenapiDoc *Openapi3T `gorm:"column:openapi_doc;comment:openapi document" json:"openapi_doc"` // openapi documentCreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in MillisecondsUpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
}// TableName PluginDraft's table name
func (*PluginDraft) TableName() string {return TableNamePluginDraft
}
ToolDraft數據模型
文件位置:backend/domain/plugin/internal/dal/model/tool_draft.gen.go
// ToolDraft tool_draft
type ToolDraft struct {ID int64 `gorm:"column:id;primaryKey;autoIncrement:true;comment:id" json:"id"` // idPluginID int64 `gorm:"column:plugin_id;not null;comment:plugin id" json:"plugin_id"` // plugin idSubURL string `gorm:"column:sub_url;comment:sub url" json:"sub_url"` // sub urlMethod string `gorm:"column:method;comment:http method" json:"method"` // http methodActivatedStatus int32 `gorm:"column:activated_status;comment:activated status" json:"activated_status"` // activated statusDebugStatus int32 `gorm:"column:debug_status;comment:debug status" json:"debug_status"` // debug statusOperation *Operation `gorm:"column:operation;comment:operation info" json:"operation"` // operation infoCreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in MillisecondsUpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
}
刪除操作中的模型特點:
- 主鍵定位:ID字段作為主鍵,是刪除操作的核心定位字段,確保精確刪除
- 權限驗證字段:DeveloperID字段用于刪除前的權限驗證,確保只有開發者可以刪除
- 關聯關系:PluginID字段建立插件與工具的關聯關系,支持級聯刪除
- 字段映射:通過gorm標簽定義字段與數據庫列的映射關系,為刪除操作提供準確的數據定位
- 約束定義:包含主鍵、非空、注釋等數據庫約束,確保刪除操作的數據完整性
- 復雜類型:Manifest和OpenapiDoc字段存儲JSON格式的復雜數據結構
- 審計追蹤:CreatedAt和UpdatedAt字段支持刪除操作的審計追蹤和時間記錄
- JSON序列化:通過json標簽支持JSON序列化,便于刪除操作的API響應和日志記錄
5.4 GORM生成的查詢接口
插件查詢接口
文件位置:backend/domain/plugin/internal/dal/query/plugin_draft.gen.go
GORM Gen工具生成的類型安全查詢接口,為刪除插件操作提供了強大的數據訪問能力。這些接口確保了刪除操作的類型安全性和執行效率。
// pluginDraft plugin_draft
type pluginDraft struct {pluginDraftDoALL field.AsteriskID field.Int64 // idSpaceID field.Int64 // space idDeveloperID field.Int64 // developer idPluginType field.Int32 // plugin typeIconURI field.String // icon uriServerURL field.String // server urlAppID field.Int64 // app idManifest field.Field // plugin manifestOpenapiDoc field.Field // openapi documentCreatedAt field.Int64 // Create Time in MillisecondsUpdatedAt field.Int64 // Update Time in MillisecondsfieldMap map[string]field.Expr
}
工具查詢接口
文件位置:backend/domain/plugin/internal/dal/query/tool_draft.gen.go
// toolDraft tool_draft
type toolDraft struct {toolDraftDoALL field.AsteriskID field.Int64 // idPluginID field.Int64 // plugin idSubURL field.String // sub urlMethod field.String // http methodActivatedStatus field.Int32 // activated statusDebugStatus field.Int32 // debug statusOperation field.Field // operation infoCreatedAt field.Int64 // Create Time in MillisecondsUpdatedAt field.Int64 // Update Time in MillisecondsfieldMap map[string]field.Expr
}
查詢接口定義
type IPluginDraftDo interface {gen.SubQueryDebug() IPluginDraftDoWithContext(ctx context.Context) IPluginDraftDoWithResult(fc func(tx gen.Dao)) gen.ResultInfoReplaceDB(db *gorm.DB)ReadDB() IPluginDraftDoWriteDB() IPluginDraftDo// 刪除操作相關方法Delete(conds ...gen.Condition) (gen.ResultInfo, error)Where(conds ...gen.Condition) IPluginDraftDo......
}type IToolDraftDo interface {gen.SubQueryDebug() IToolDraftDoWithContext(ctx context.Context) IToolDraftDo// 刪除操作相關方法Delete(conds ...gen.Condition) (gen.ResultInfo, error)Where(conds ...gen.Condition) IToolDraftDo......
}
刪除操作相關接口特點:
- Delete方法:提供類型安全的刪除操作,支持條件刪除
- Where條件:支持復雜的刪除條件構建,確保精確刪除
- 上下文支持:WithContext方法支持請求上下文傳遞
- 事務支持:支持在事務中執行刪除操作,確保數據一致性
- 調試支持:Debug方法便于刪除操作的SQL調試和優化
- 關聯刪除:ToolDraft通過PluginID字段支持級聯刪除操作
5.5 統一查詢入口
文件位置:backend\domain\plugin\internal\dal\query\gen.go
該文件為刪除插件操作提供了統一的查詢入口和事務支持,確保刪除操作的一致性和可靠性。
核心代碼:
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.package queryimport ("context""database/sql""gorm.io/gorm""gorm.io/gen""gorm.io/plugin/dbresolver"
)var (Q = new(Query)PluginDraft *pluginDraftToolDraft *toolDraft
)func SetDefault(db *gorm.DB, opts ...gen.DOOption) {*Q = *Use(db, opts...)PluginDraft = &Q.PluginDraftToolDraft = &Q.ToolDraft
}func Use(db *gorm.DB, opts ...gen.DOOption) *Query {return &Query{db: db,PluginDraft: newPluginDraft(db, opts...),ToolDraft: newToolDraft(db, opts...),}
}type Query struct {db *gorm.DBPluginDraft pluginDraftToolDraft toolDraft
}func (q *Query) Available() bool { return q.db != nil }func (q *Query) clone(db *gorm.DB) *Query {return &Query{db: db,PluginDraft: q.PluginDraft.clone(db),ToolDraft: q.ToolDraft.clone(db),}
}func (q *Query) ReadDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
}func (q *Query) WriteDB() *Query {return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
}func (q *Query) ReplaceDB(db *gorm.DB) *Query {return &Query{db: db,PluginDraft: q.PluginDraft.replaceDB(db),ToolDraft: q.ToolDraft.replaceDB(db),}
}type queryCtx struct {PluginDraft IPluginDraftDoToolDraft IToolDraftDo
}func (q *Query) WithContext(ctx context.Context) *queryCtx {return &queryCtx{PluginDraft: q.PluginDraft.WithContext(ctx),ToolDraft: q.ToolDraft.WithContext(ctx),}
}func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {tx := q.db.Begin(opts...)return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}type QueryTx struct {*QueryError error
}func (q *QueryTx) Commit() error {return q.db.Commit().Error
}func (q *QueryTx) Rollback() error {return q.db.Rollback().Error
}func (q *QueryTx) SavePoint(name string) error {return q.db.SavePoint(name).Error
}func (q *QueryTx) RollbackTo(name string) error {return q.db.RollbackTo(name).Error
}
刪除操作查詢入口特點:
- 全局查詢對象:提供全局的PluginDraft和ToolDraft查詢對象,便于刪除操作的統一管理
- 事務支持:Transaction方法支持在事務中執行刪除操作,確保數據一致性
- 讀寫分離:ReadDB和WriteDB方法支持數據庫讀寫分離,刪除操作使用WriteDB
- 上下文傳遞:WithContext方法支持請求上下文在刪除操作中的傳遞
- 數據庫切換:ReplaceDB方法支持動態切換數據庫連接,便于多環境部署
- 事務管理:Begin、Commit、Rollback等方法提供完整的事務管理能力
- 多表支持:同時支持PluginDraft和ToolDraft兩個表的查詢操作
5.6 數據訪問層刪除操作架構總結
刪除插件在數據訪問層的實現體現了現代Go應用的最佳實踐:
技術特點:
- 類型安全:使用GORM Gen生成類型安全的查詢接口,避免SQL注入和類型錯誤
- 分層設計:Repository接口抽象數據訪問,DAO實現具體的數據庫操作
- 錯誤處理:統一的錯誤碼包裝機制,便于上層進行錯誤分類和處理
- 事務支持:完整的事務支持,確保刪除操作的原子性
- 性能優化:精確的WHERE條件和索引利用,確保刪除操作的高效執行
- 級聯刪除:支持插件及其關聯工具的級聯刪除操作
安全保障:
- 權限驗證:通過DeveloperID字段確保只有開發者可以刪除自己的插件
- 存在性檢查:刪除前驗證插件是否存在,避免無效刪除
- 物理刪除:徹底從數據庫中移除記錄,確保數據清理的完整性
- 審計追蹤:完整的時間戳記錄,支持刪除操作的審計和追蹤
- 關聯清理:確保刪除插件時同時清理相關的工具數據
刪除操作流程:
- 接口調用:上層通過Repository接口調用DeleteDraftPlugin方法
- 事務開啟:開啟數據庫事務確保操作的原子性
- 級聯刪除:先刪除關聯的工具數據,再刪除插件數據
- 事務提交:所有刪除操作成功后提交事務
- 錯誤處理:任何步驟失敗都會回滾事務并返回錯誤
這種設計確保了刪除插件操作的安全性、可靠性和高性能,為上層業務邏輯提供了堅實的數據訪問基礎。
數據模型與查詢文件依賴關系
數據庫表結構 (schema.sql)(plugin_draft、tool_draft表)↓ gen_orm_query.go
模型文件 (model/plugin_draft.gen.go, model/tool_draft.gen.go) - 生成模型↓
查詢文件 (query/plugin_draft.gen.go, query/tool_draft.gen.go) - 依賴對應模型↓
統一入口 (query/gen.go) - 依賴所有查詢文件
數據訪問層架構總結
分層架構:
業務服務層 (Service)↓
倉儲接口層 (Repository Interface)↓
數據訪問層 (DAO Implementation)↓
GORM查詢層 (Generated Query)↓
數據模型層 (Generated Model)↓
數據庫層 (MySQL)
刪除插件在數據訪問層的完整流程:
- 接口定義:
PluginRepository.DeleteDraftPlugin(ctx, ID)
定義刪除操作契約 - DAO實現:
PluginDraftDAO.DeleteWithTX(tx, ID)
和ToolDraftDAO.DeleteAllWithTX(tx, pluginID)
實現具體刪除邏輯 - 事務管理:使用事務確保插件和工具數據的一致性刪除
- 級聯刪除:先刪除工具數據,再刪除插件數據
- 錯誤處理:包裝刪除異常為統一錯誤碼
- 結果返回:刪除成功返回nil,失敗返回包裝后的錯誤
設計優勢:
- 接口抽象:通過Repository接口實現數據訪問的抽象化
- 代碼生成:使用GORM Gen自動生成類型安全的查詢代碼
- 錯誤處理:統一的錯誤包裝和處理機制
- 事務支持:通過context傳遞支持數據庫事務
- 刪除安全:通過ID精確定位,避免誤刪除操作
- 性能優化:合理的索引設計和查詢優化
- 可測試性:清晰的分層結構便于單元測試
- 可維護性:代碼生成減少手工編寫,降低維護成本
- 級聯刪除:支持插件及其關聯數據的級聯刪除
刪除操作的技術特點:
- 物理刪除:當前實現為物理刪除,直接從數據庫中移除記錄
- 事務操作:使用數據庫事務確保插件和工具數據的一致性刪除
- 索引優化:基于主鍵ID的刪除操作,具有最佳的查詢性能
- 錯誤分類:通過錯誤碼區分不同類型的刪除異常
- 審計支持:可通過數據庫日志追蹤刪除操作的執行情況
- 關聯清理:確保刪除插件時同時清理相關的工具數據
6. 基礎設施層
基礎設施層為插件刪除功能提供了核心的技術支撐,包括數據庫連接、緩存管理、搜索引擎和事件處理等關鍵組件。這些組件通過契約層(Contract)和實現層(Implementation)的分離設計,確保了刪除操作的可靠性、一致性和高性能。
6.1 數據庫基礎設施
數據庫契約層
文件位置:backend/infra/contract/orm/database.go
package ormimport ("gorm.io/gorm"
)type DB = gorm.DB
設計作用:
- 為GORM數據庫對象提供類型別名,統一數據庫接口
- 作為契約層抽象,便于后續數據庫實現的替換
- 為插件相關的數據訪問層提供統一的數據庫連接接口
MySQL數據庫實現
文件位置:backend/infra/impl/mysql/mysql.go
package mysqlimport ("fmt""os""gorm.io/driver/mysql""gorm.io/gorm"
)func New() (*gorm.DB, error) {dsn := os.Getenv("MYSQL_DSN")db, err := gorm.Open(mysql.Open(dsn))if err != nil {return nil, fmt.Errorf("mysql open, dsn: %s, err: %w", dsn, err)}return db, nil
}
在插件刪除中的作用:
- 為
PluginDraftDAO
和ToolDraftDAO
提供數據庫連接,支持插件的刪除操作 - 通過GORM ORM框架,執行安全的
plugin_draft
和tool_draft
表刪除操作 - 支持事務處理,確保插件刪除過程的數據一致性和原子性
- 連接池管理,提高插件并發刪除的性能和穩定性
- 支持級聯刪除,確保插件和相關工具數據的一致性清理
刪除操作初始化流程:
main.go → application.Init() → appinfra.Init() → mysql.New() → PluginDAO注入 → 執行刪除
6.2 ID生成器基礎設施
ID生成器契約層
文件位置:backend/infra/contract/idgen/idgen.go
package idgenimport ("context"
)type IDGenerator interface {GenID(ctx context.Context) (int64, error)GenMultiIDs(ctx context.Context, counts int) ([]int64, error)
}
ID生成器實現
文件位置:backend/infra/impl/idgen/idgen.go
type idGenImpl struct {cli cache.Cmdablenamespace string
}func (i *idGenImpl) GenID(ctx context.Context) (int64, error) {ids, err := i.GenMultiIDs(ctx, 1)if err != nil {return 0, err}return ids[0], nil
}func (i *idGenImpl) GenMultiIDs(ctx context.Context, counts int) ([]int64, error) {// 基于時間戳+計數器+服務器ID的分布式ID生成算法// ID格式:[32位秒級時間戳][10位毫秒][8位計數器][14位服務器ID]// ...
}
在插件刪除中的作用:
- 雖然刪除操作不需要生成新ID,但ID生成器為刪除操作提供了重要支撐
- 在刪除事件發布時,為事件生成唯一的事件ID,確保事件處理的冪等性
- 支持刪除操作的審計日志ID生成,便于操作追蹤和問題排查
- 為刪除相關的臨時資源(如刪除任務、回滾記錄)生成唯一標識
- 為插件刪除過程中的中間狀態記錄生成唯一標識
刪除操作中的ID使用流程:
PluginService.DeleteDraftPlugin() → 驗證插件ID → 執行刪除 → 生成事件ID → 發布刪除事件
6.3 緩存系統基礎設施
緩存契約層
文件位置:backend/infra/contract/cache/cache.go
package cachetype Cmdable interface {Pipeline() PipelinerStringCmdableHashCmdableGenericCmdableListCmdable
}type StringCmdable interface {Set(ctx context.Context, key string, value interface{}, expiration time.Duration) StatusCmdGet(ctx context.Context, key string) StringCmdIncrBy(ctx context.Context, key string, value int64) IntCmd
}
Redis緩存實現
文件位置:backend/infra/impl/cache/redis/redis.go
func New() cache.Cmdable {addr := os.Getenv("REDIS_ADDR")password := os.Getenv("REDIS_PASSWORD")return NewWithAddrAndPassword(addr, password)
}func NewWithAddrAndPassword(addr, password string) cache.Cmdable {rdb := redis.NewClient(&redis.Options{Addr: addr,Password: password,PoolSize: 100,MinIdleConns: 10,MaxIdleConns: 30,ConnMaxIdleTime: 5 * time.Minute,DialTimeout: 5 * time.Second,ReadTimeout: 3 * time.Second,WriteTimeout: 3 * time.Second,})return &redisImpl{client: rdb}
}
在插件刪除中的作用:
- 權限驗證緩存:緩存用戶權限信息,快速驗證刪除權限
- 插件信息緩存:緩存待刪除插件的基本信息,減少數據庫查詢
- 分布式鎖:防止并發刪除同一插件,確保刪除操作的原子性
- 刪除狀態緩存:臨時存儲刪除操作的狀態,支持刪除進度查詢
- 事件去重:緩存已處理的刪除事件ID,避免重復處理
- 關聯數據緩存:緩存插件關聯的工具信息,優化級聯刪除性能
刪除操作緩存使用場景:
1. 權限緩存:user_perm:{user_id}:{space_id}:{plugin_id}
2. 插件緩存:plugin_info:{plugin_id}
3. 刪除鎖:lock:plugin_delete:{plugin_id}
4. 刪除狀態:delete_status:{plugin_id}:{operation_id}
5. 事件去重:event_processed:{event_id}
6. 工具關聯:plugin_tools:{plugin_id}
6.4 ElasticSearch搜索基礎設施
ElasticSearch契約層
文件位置:backend/infra/contract/es/es.go
package estype Client interface {Create(ctx context.Context, index, id string, document any) errorUpdate(ctx context.Context, index, id string, document any) errorDelete(ctx context.Context, index, id string) errorSearch(ctx context.Context, index string, req *Request) (*Response, error)Exists(ctx context.Context, index string) (bool, error)CreateIndex(ctx context.Context, index string, properties map[string]any) error
}type BulkIndexer interface {Add(ctx context.Context, item BulkIndexerItem) errorClose(ctx context.Context) error
}
ElasticSearch實現層
文件位置:backend/infra/impl/es/es_impl.go
func New() (es.Client, error) {version := os.Getenv("ES_VERSION")switch version {case "7":return newES7Client()case "8":return newES8Client()default:return newES8Client() // 默認使用ES8}
}
在插件刪除中的作用:
- 索引刪除:將刪除的插件從ES的
coze_resource
索引中移除 - 搜索結果更新:確保刪除的插件不再出現在搜索結果中
- 關聯數據清理:清理與刪除插件相關的搜索索引和元數據
- 實時同步:插件刪除后實時從搜索引擎中移除
- 批量刪除:支持批量刪除插件時的批量索引清理
- 工具索引清理:同時清理插件關聯的工具索引數據
刪除操作的索引處理:
{"operation": "delete","res_id": 123456789,"res_type": 1,"delete_time": 1703123456789,"operator_id": 987654321,"space_id": 111222333
}
刪除索引執行流程:
1. 用戶刪除插件 → API Gateway → PluginService.DeleteDraftPlugin()
2. 執行數據庫刪除 → 發布刪除事件 → ES刪除處理器
3. 構建刪除請求 → esClient.Delete(ctx, "coze_resource", pluginID)
4. 索引清理 → 驗證刪除結果 → 記錄刪除日志
6.5 基礎設施層架構優勢
依賴倒置原則
- 契約層抽象:業務層依賴接口而非具體實現
- 實現層解耦:可以靈活替換數據庫、緩存、搜索引擎的具體實現
- 測試友好:通過Mock接口進行單元測試
配置驅動
- 環境變量配置:通過環境變量控制各組件的連接參數
- 版本兼容:支持ES7/ES8版本切換,數據庫驅動切換
- 性能調優:連接池、超時時間等參數可配置
高可用設計
- 連接池管理:數據庫和Redis連接池,提高并發性能
- 錯誤處理:完善的錯誤處理和重試機制
- 監控支持:提供性能指標和健康檢查接口
擴展性支持
- 水平擴展:分布式ID生成支持多實例部署
- 存儲擴展:支持分庫分表、讀寫分離
- 搜索擴展:支持ES集群部署和索引分片
這種基礎設施層的設計為插件刪除功能提供了穩定、高效、可擴展的技術底座,確保了刪除操作在高并發場景下的安全性、一致性和可靠性。