Skip to content

feat: DMS↔ODC 用户同步自愈(策略 A+B) - #657

Open
LordofAvernus wants to merge 1 commit into
mainfrom
dms/feat-948
Open

feat: DMS↔ODC 用户同步自愈(策略 A+B)#657
LordofAvernus wants to merge 1 commit into
mainfrom
dms/feat-948

Conversation

@LordofAvernus

@LordofAvernus LordofAvernus commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

User description

关联的 issue

https://github.com/actiontech/dms-ee/issues/948

描述你的变更

  • 进台缓存未命中时先查后建 + 创建冲突再查绑定(策略 A),解除映射缺失与 ODC 同名残留死锁
  • 删除 DMS 用户时清理 SqlWorkbench 缓存/会话,并对 ODC 对应用户禁用而非删除(策略 B)
  • 客户端增补 ListUsers / SetUserEnabled / ResetUserPassword 与冲突错误识别

确认项(pr提交后操作)

Tip

请在指定复审人之前,确认并完成以下事项,完成后✅


  • 我已完成自测
  • 我已记录完整日志方便进行诊断
  • 我已在关联的issue里补充了实现方案
  • 我已在关联的issue里补充了测试影响面
  • 我已确认了变更的兼容性,如果不兼容则在issue里标记 not_compatible
  • 我已确认了是否要更新文档,如果要更新则在issue里标记 need_update_doc

Made with Cursor


Description

  • 增强 DMS 与 ODC 用户同步自愈的双策略机制

  • 策略 A:先查询再创建用户,处理创建冲突并绑定已存在用户

  • 策略 B:删除 DMS 用户时清理 SqlWorkbench 缓存和会话,并对 ODC 用户禁用

  • 新增 ODC 用户操作接口及错误处理,提升系统容错性


Diagram Walkthrough

flowchart LR
  A["DMS用户操作"] -->|登录/创建| B["策略 A:查询/创建/绑定"]
  A -->|删除用户| C["策略 B:清理缓存 & 禁用ODC用户"]
  B -- 成功绑定 --> D["保存SqlWorkbench用户缓存"]
  C -- 清理成功 --> E["更新会话/日志"]
Loading

File Walkthrough

Relevant files
Enhancement
router.go
注入并连接生命周期清理能力                                                                                       

internal/apiserver/service/router.go

  • 注入 SqlWorkbenchLifecycle 实例
  • 连接 DMSController 与 SqlWorkbenchService 清理能力
+3/-0     
sql_workbench_client.go
增强 ODC 用户接口与冲突错误处理                                                                             

internal/sql_workbench/client/sql_workbench_client.go

  • 新增 CreateUsersConflictError 错误类型及辅助函数
  • 实现 ListUsers、SetUserEnabled、ResetUserPassword 接口
  • 增强用户创建冲突处理逻辑(策略 A 补充)
+294/-2 
sql_workbench_service.go
重构用户创建、绑定及删除清理逻辑                                                                                 

internal/sql_workbench/service/sql_workbench_service.go

  • 重构 ensureSqlWorkbenchUser 以支持先查后创及冲突绑定
  • 引入锁机制控制并发用户创建(lockEnsureSqlWorkbenchUser)
  • 增加 ensureSqlWorkbenchUserUsable 方法确保用户可用性
  • 实现 CleanupOnDMSUserDelete 清理策略 B 和 disableODCUserOnDMSDelete 方法
+198/-16
Bug fix
user.go
添加用户缓存清理及生命周期接口                                                                                   

internal/dms/biz/user.go

  • 新增 DeleteSqlWorkbenchUserCache 接口
  • 新增 DeleteSqlWorkbenchDatasourceCachesByUserID 方法
  • 引入 SqlWorkbenchLifecycle 接口及注入方法
  • 删除用户时调用清理 SqlWorkbench 缓存和禁用 ODC 用户
+20/-0   
sql_workbench.go
添加 SqlWorkbench 缓存删除方法                                                                     

internal/dms/storage/sql_workbench.go

  • 增加 DeleteSqlWorkbenchUserCache 方法
  • 增加 DeleteSqlWorkbenchDatasourceCachesByUserID 方法
  • 实现对缓存的删除操作,支持策略 B
+18/-0   

进台缓存未命中时先查后建并冲突兜底;删除用户时清理工作台缓存并对 ODC 用户禁用。
关联 actiontech/dms-ee#948

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

⏱️ Estimated effort to review: 5 🔵🔵🔵🔵🔵
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@github-actions

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
移除重复解析

建议去除首次对响应体进行 JSON 解析后忽略错误的部分,并只在需要解析时执行一次 JSON 解析。这样可以避免重复解析,也能及时捕获解析错误,降低潜在的数据异常风险。

internal/sql_workbench/client/sql_workbench_client.go [611-633]

 body, err := io.ReadAll(resp.Body)
 if err != nil {
     c.log.Errorf("Failed to read create users response: %v", err)
     return nil, fmt.Errorf("failed to read create users response: %v", err)
 }
 
-var createUsersResp CreateUsersResponse
-_ = json.Unmarshal(body, &createUsersResp)
-
 // 检查HTTP状态码
 if resp.StatusCode != http.StatusOK {
     c.log.Errorf("Create users failed with status code: %d, response: %s", resp.StatusCode, string(body))
+    var createUsersResp CreateUsersResponse
     if isCreateUsersDuplicatedResponse(resp.StatusCode, body, &createUsersResp) {
         return nil, newCreateUsersConflictError(resp.StatusCode, &createUsersResp, body)
     }
     return nil, fmt.Errorf("create users failed with status code: %d", resp.StatusCode)
 }
 
 // 解析响应(HTTP 200 时要求结构合法)
+var createUsersResp CreateUsersResponse
 if err := json.Unmarshal(body, &createUsersResp); err != nil {
     c.log.Errorf("Failed to parse create users response: %v", err)
     return nil, fmt.Errorf("failed to parse create users response: %v", err)
 }
Suggestion importance[1-10]: 6

__

Why: The suggestion removes the redundant JSON unmarshal call, improving error handling and reducing unnecessary work in the CreateUsers method.

Low
添加锁清理机制

建议考虑为 ensureUserLocks 添加清理机制,防止随着不同账户的不断锁定而在 sync.Map
中累积大量未释放的锁,从而可能引发内存泄漏问题。可以在解锁后尝试删除相应的锁对象或定期清理不再使用的项。

internal/sql_workbench/service/sql_workbench_service.go [68-73]

 func lockEnsureSqlWorkbenchUser(accountName string) func() {
     v, _ := ensureUserLocks.LoadOrStore(accountName, &sync.Mutex{})
     mu := v.(*sync.Mutex)
     mu.Lock()
-    return mu.Unlock
+    return func() {
+        mu.Unlock()
+        // 可选:解锁后尝试删除当前账户的锁,需确保不会引入并发问题
+        ensureUserLocks.Delete(accountName)
+    }
 }
Suggestion importance[1-10]: 5

__

Why: The suggestion adds an optional lock cleanup step to prevent potential memory buildup in ensureUserLocks, though it should be applied carefully to avoid concurrency issues.

Low

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant