feat(runner): implement cluster mode with Redis-based task dispatching and registry
All checks were successful
Build Backend / build (push) Successful in 2m22s
Build Backend / build-docker (push) Successful in 1m20s

Introduce a distributed task execution system for gRPC runners. This includes:
- A `TaskBus` for cluster-mode task dispatching via Redis Pub/Sub.
- A `RunnerRegistry` to track active runner instances in Redis.
- Support for both standalone and cluster modes via configuration.
- Refactored `RunnerHub` and `TaskManager` to use a `TaskDispatcher` interface, decoupling task submission from local execution.
- Added distributed locking to `HotRankWorker` to ensure only one instance performs periodic hot rank recalculations in a multi-instance deployment.
- Updated dependency injection (Wire) to support the new runner components and registry.
This commit is contained in:
2026-05-07 01:08:39 +08:00
parent dc27eb5cde
commit 8aa85ca4b2
15 changed files with 1125 additions and 86 deletions

View File

@@ -1764,6 +1764,50 @@ func (h *GroupHandler) HandleSetGroupAvatar(c *gin.Context) {
response.Success(c, dto.GroupToResponse(group))
}
// HandleSetGroupDescription 设置群描述
// PUT /api/v1/groups/:id/description
func (h *GroupHandler) HandleSetGroupDescription(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
}
var params dto.SetGroupDescriptionParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
updates := map[string]any{
"description": params.Description,
}
err := h.groupService.UpdateGroup(userID, groupID, updates)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "没有权限修改群组信息")
return
}
if errors.Is(err, service.ErrGroupNotFound) {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取更新后的群组信息
group, _ := h.groupService.GetGroupByID(groupID)
response.Success(c, dto.GroupToResponse(group))
}
// HandleSetGroupLeave 退出群组
// POST /api/v1/groups/:id/leave
func (h *GroupHandler) HandleSetGroupLeave(c *gin.Context) {