docs: 修复OnExhibitionCompleted 调用链路重建
This commit is contained in:
parent
afb235afd3
commit
d30eda151e
471
docs/fix/2026-05-16_OnExhibitionCompleted修复文档.md
Normal file
471
docs/fix/2026-05-16_OnExhibitionCompleted修复文档.md
Normal file
@ -0,0 +1,471 @@
|
|||||||
|
# 修复文档:OnExhibitionCompleted 调用链路重建
|
||||||
|
|
||||||
|
**日期**: 2026-05-16
|
||||||
|
**问题**: OnExhibitionCompleted 未被调用,用户累计上架时长 (user_exhibition_hours) 数据异常
|
||||||
|
**影响**: 61 次重复调用记录,8 条有效记录 vs 53 小时重复累计
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、问题根因
|
||||||
|
|
||||||
|
### 1.1 当前代码状态(经验证)
|
||||||
|
|
||||||
|
| 组件 | 状态 | 位置 | 备注 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| OnExhibitionCompleted RPC 定义 | ✅ 存在 | `galleryService/client/task_rpc_client.go:51` | 完整实现,但从未被调用 |
|
||||||
|
| OnExhibitionCompleted 调用处 | ❌ 不存在 | **无任何代码调用** | 已搜索全项目无调用 |
|
||||||
|
| CleanupWorker NewCleanupWorker 调用 | ⚠️ 存在但实现缺失 | `main.go:183` | 调用了但 `service/cleanup_worker.go` 不存在 |
|
||||||
|
| AddExhibitionHours 调用 | ❌ 缺失 | `revenue_service.go:132-172` | OnExhibitionCompleted 未调用 |
|
||||||
|
| revenueService.userClient | ✅ 已注入 | `service/revenue_service.go:23` | |
|
||||||
|
| main.go 调用签名不匹配 | ⚠️ 存在 | `main.go:110` | 传3个参数,函数只接收2个 |
|
||||||
|
|
||||||
|
### 1.2 数据流断点
|
||||||
|
|
||||||
|
```
|
||||||
|
展位过期 → main.go 调用 NewCleanupWorker
|
||||||
|
↓
|
||||||
|
cleanup_worker.go 不存在
|
||||||
|
↓
|
||||||
|
无人调用 taskClient.OnExhibitionCompleted()
|
||||||
|
↓
|
||||||
|
OnExhibitionCompleted RPC 从未被触发
|
||||||
|
↓
|
||||||
|
revenueService.OnExhibitionCompleted 只创建 revenue record
|
||||||
|
↓
|
||||||
|
缺少: s.userClient.AddExhibitionHours()
|
||||||
|
↓
|
||||||
|
user_exhibition_hours 表无数据来源
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 验证过程
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. 搜索 OnExhibitionCompleted 调用 - 找到定义但无调用
|
||||||
|
grep -rn "\.OnExhibitionCompleted\(" backend/services/galleryService/
|
||||||
|
# 结果: task_rpc_client.go:77 是定义,其他都是 RPC handler
|
||||||
|
|
||||||
|
# 2. 确认 taskClient.OnExhibitionCompleted 无人调用
|
||||||
|
grep -rn "taskClient\.OnExhibitionCompleted\|taskRPCClient\.OnExhibitionCompleted" backend/
|
||||||
|
# 结果: 无匹配
|
||||||
|
|
||||||
|
# 3. 检查 service/ 目录文件
|
||||||
|
ls backend/services/galleryService/service/
|
||||||
|
# 结果: 只有 gallery_service.go,没有 cleanup_worker.go
|
||||||
|
|
||||||
|
# 4. 检查 revenueService 结构
|
||||||
|
grep -A 5 "type revenueService struct" backend/services/taskService/service/revenue_service.go
|
||||||
|
# 结果:
|
||||||
|
# type revenueService struct {
|
||||||
|
# revenueRepo repository.RevenueRepository
|
||||||
|
# userClient client.UserServiceClient ✅ 已注入
|
||||||
|
# }
|
||||||
|
|
||||||
|
# 5. 检查 AddExhibitionHours 调用位置
|
||||||
|
grep -n "AddExhibitionHours" backend/services/taskService/service/revenue_service.go
|
||||||
|
# 结果: 无匹配 - 确认未调用
|
||||||
|
|
||||||
|
# 6. 检查 main.go 签名不匹配
|
||||||
|
grep "NewRevenueService" backend/services/taskService/main.go
|
||||||
|
# 结果: main.go:110 传3个参数 (revenueRepo, userRPCClient, galleryRPCClient)
|
||||||
|
|
||||||
|
grep "func NewRevenueService" backend/services/taskService/service/revenue_service.go
|
||||||
|
# 结果: revenue_service.go:26 只接收2个参数 (revenueRepo, userClient)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.4 风险分析
|
||||||
|
|
||||||
|
如果直接修复代码让 RemoveExhibitionByAsset 或 cleanup worker 调用 AddExhibitionHours:
|
||||||
|
- 基于当前 61 条记录,会重复累计约 53 小时(61 - 8 = 53 小时的重复)
|
||||||
|
- 需要先清理重复数据或添加去重机制
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、修复方案
|
||||||
|
|
||||||
|
### 2.1 修复步骤
|
||||||
|
|
||||||
|
#### Step 1: 创建 `backend/services/galleryService/service/cleanup_worker.go`
|
||||||
|
|
||||||
|
```go
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/topfans/backend/pkg/logger"
|
||||||
|
"github.com/topfans/backend/pkg/models"
|
||||||
|
"github.com/topfans/backend/services/galleryService/client"
|
||||||
|
"github.com/topfans/backend/services/galleryService/repository"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CleanupWorker struct {
|
||||||
|
repo *repository.GalleryRepository
|
||||||
|
assetClient client.AssetRPCClient
|
||||||
|
userClient client.UserRPCClient
|
||||||
|
taskClient client.TaskRPCClient
|
||||||
|
stopCh chan struct{}
|
||||||
|
ticker *time.Ticker
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCleanupWorker(
|
||||||
|
repo *repository.GalleryRepository,
|
||||||
|
assetClient client.AssetRPCClient,
|
||||||
|
userClient client.UserRPCClient,
|
||||||
|
taskClient client.TaskRPCClient,
|
||||||
|
) *CleanupWorker {
|
||||||
|
return &CleanupWorker{
|
||||||
|
repo: repo,
|
||||||
|
assetClient: assetClient,
|
||||||
|
userClient: userClient,
|
||||||
|
taskClient: taskClient,
|
||||||
|
stopCh: make(chan struct{}),
|
||||||
|
ticker: time.NewTicker(1 * time.Minute),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CleanupWorker) Start() {
|
||||||
|
logger.Logger.Info("CleanupWorker started")
|
||||||
|
w.cleanup() // 立即执行一次
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-w.ticker.C:
|
||||||
|
w.cleanup()
|
||||||
|
case <-w.stopCh:
|
||||||
|
logger.Logger.Info("CleanupWorker stopped")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CleanupWorker) Stop() {
|
||||||
|
w.ticker.Stop()
|
||||||
|
close(w.stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CleanupWorker) cleanup() {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 获取所有过期展品 (使用毫秒时间戳)
|
||||||
|
nowMs := time.Now().UnixMilli()
|
||||||
|
expiredExhibitions, err := w.repo.GetExpiredExhibitions(nowMs)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Error("CleanupWorker: failed to get expired exhibitions", zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expiredExhibitions) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Logger.Info("CleanupWorker: processing expired exhibitions", zap.Int("count", len(expiredExhibitions)))
|
||||||
|
|
||||||
|
for _, exhibition := range expiredExhibitions {
|
||||||
|
w.processExpiredExhibition(ctx, exhibition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *CleanupWorker) processExpiredExhibition(ctx context.Context, exhibition *models.Exhibition) {
|
||||||
|
// 获取展位信息
|
||||||
|
slot, err := w.repo.GetSlotByID(exhibition.SlotID)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Error("CleanupWorker: failed to get slot",
|
||||||
|
zap.Int64("slot_id", exhibition.SlotID), zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算实际上架时长(毫秒转小时)
|
||||||
|
startTime := exhibition.PlacedAt.UnixMilli()
|
||||||
|
expireAt := exhibition.ExpiresAt.UnixMilli()
|
||||||
|
actualHours := (expireAt - startTime) / 3600000 // 毫秒转小时
|
||||||
|
if actualHours < 1 {
|
||||||
|
actualHours = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求
|
||||||
|
req := &client.OnExhibitionCompletedRequest{
|
||||||
|
ExhibitionId: exhibition.ID,
|
||||||
|
AssetId: exhibition.AssetID,
|
||||||
|
SlotId: exhibition.SlotID,
|
||||||
|
OccupierUid: exhibition.OccupierUID,
|
||||||
|
OccupierStarId: exhibition.OccupierStarID,
|
||||||
|
SlotOwnerUid: slot.UserID,
|
||||||
|
CrystalAmount: exhibition.CrystalAmount,
|
||||||
|
StartTime: startTime,
|
||||||
|
ExpireAt: expireAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用 OnExhibitionCompleted - 这是缺失的关键调用
|
||||||
|
resp, err := w.taskClient.OnExhibitionCompleted(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Error("CleanupWorker: OnExhibitionCompleted failed",
|
||||||
|
zap.Int64("exhibition_id", exhibition.ID), zap.Error(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Logger.Info("CleanupWorker: OnExhibitionCompleted succeeded",
|
||||||
|
zap.Int64("exhibition_id", exhibition.ID),
|
||||||
|
zap.Int64("revenue_record_id", resp.RevenueRecordId))
|
||||||
|
|
||||||
|
// 删除展品记录
|
||||||
|
if err := w.repo.DeleteExhibition(exhibition.ID); err != nil {
|
||||||
|
logger.Logger.Error("CleanupWorker: failed to delete exhibition",
|
||||||
|
zap.Int64("exhibition_id", exhibition.ID), zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 2: 修改 `revenue_service.go` 添加 AddExhibitionHours 调用
|
||||||
|
|
||||||
|
**文件**: `backend/services/taskService/service/revenue_service.go`
|
||||||
|
|
||||||
|
在 `OnExhibitionCompleted` 成功创建 revenue record 后,添加 `AddExhibitionHours` 调用:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (s *revenueService) OnExhibitionCompleted(ctx context.Context, req *pb.OnExhibitionCompletedRequest) (*pb.OnExhibitionCompletedResponse, error) {
|
||||||
|
// ... 现有代码 (检查 self-slot,创建 revenue record) ...
|
||||||
|
|
||||||
|
result, err := s.revenueRepo.CreateRevenueRecord(record)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Error("OnExhibitionCompleted: failed to create revenue record",
|
||||||
|
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
||||||
|
zap.Int64("amount", req.CrystalAmount),
|
||||||
|
zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 新增:调用 AddExhibitionHours =====
|
||||||
|
// 计算实际上架时长(毫秒转小时)
|
||||||
|
startTime := req.StartTime
|
||||||
|
expireAt := req.ExpireAt
|
||||||
|
actualHours := (expireAt - startTime) / 3600000
|
||||||
|
if actualHours < 1 {
|
||||||
|
actualHours = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// sourceID 用于去重,避免重复累计
|
||||||
|
sourceID := fmt.Sprintf("exhibition_%d", req.ExhibitionId)
|
||||||
|
|
||||||
|
// 增加用户累计上架时长(收益属于展位主人)
|
||||||
|
newLevel, levelDelta, crystalReward, err := s.userClient.AddExhibitionHours(
|
||||||
|
ctx,
|
||||||
|
req.SlotOwnerUid,
|
||||||
|
req.OccupierStarId,
|
||||||
|
actualHours,
|
||||||
|
sourceID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Error("OnExhibitionCompleted: AddExhibitionHours failed",
|
||||||
|
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
||||||
|
zap.Int64("hours", actualHours),
|
||||||
|
zap.Error(err))
|
||||||
|
// 不返回错误,因为收益记录已创建
|
||||||
|
} else {
|
||||||
|
logger.Logger.Info("OnExhibitionCompleted: AddExhibitionHours succeeded",
|
||||||
|
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
||||||
|
zap.Int64("hours", actualHours),
|
||||||
|
zap.Int32("new_level", newLevel),
|
||||||
|
zap.Int32("level_delta", levelDelta),
|
||||||
|
zap.Int64("crystal_reward", crystalReward))
|
||||||
|
}
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
logger.Logger.Info("OnExhibitionCompleted: revenue record created",
|
||||||
|
zap.Int64("record_id", result.ID),
|
||||||
|
zap.Int64("slot_owner_uid", req.SlotOwnerUid),
|
||||||
|
zap.Int64("amount", req.CrystalAmount))
|
||||||
|
|
||||||
|
return &pb.OnExhibitionCompletedResponse{RevenueRecordId: result.ID}, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**: 需要在文件头部添加 `fmt` import:
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt" // 新增
|
||||||
|
// ...
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Step 3: 修复 main.go 签名不匹配
|
||||||
|
|
||||||
|
**文件**: `backend/services/taskService/main.go:110`
|
||||||
|
|
||||||
|
当前代码:
|
||||||
|
```go
|
||||||
|
revenueSvc := service.NewRevenueService(revenueRepo, userRPCClient, galleryRPCClient)
|
||||||
|
```
|
||||||
|
|
||||||
|
有两种修复方式:
|
||||||
|
|
||||||
|
**方式 A**: 如果 `galleryRPCClient` 不需要,从调用中移除:
|
||||||
|
```go
|
||||||
|
revenueSvc := service.NewRevenueService(revenueRepo, userRPCClient)
|
||||||
|
```
|
||||||
|
|
||||||
|
**方式 B**: 如果需要 `galleryRPCClient`,修改 `NewRevenueService` 签名:
|
||||||
|
```go
|
||||||
|
func NewRevenueService(revenueRepo repository.RevenueRepository, userClient client.UserServiceClient, galleryClient client.GalleryServiceClient) RevenueService {
|
||||||
|
return &revenueService{
|
||||||
|
revenueRepo: revenueRepo,
|
||||||
|
userClient: userClient,
|
||||||
|
galleryClient: galleryClient, // 新增字段
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、数据修复
|
||||||
|
|
||||||
|
### 3.1 重复数据清理
|
||||||
|
|
||||||
|
在修复代码之前,需要先处理现有的重复数据:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 查看重复记录
|
||||||
|
SELECT
|
||||||
|
user_id,
|
||||||
|
star_id,
|
||||||
|
source_id,
|
||||||
|
COUNT(*) as cnt,
|
||||||
|
SUM(exhibition_hours) as total_hours
|
||||||
|
FROM user_exhibition_hours
|
||||||
|
WHERE source_id LIKE 'exhibition_%'
|
||||||
|
GROUP BY user_id, star_id, source_id
|
||||||
|
HAVING COUNT(*) > 1;
|
||||||
|
|
||||||
|
-- 保留最新记录,删除重复
|
||||||
|
DELETE FROM user_exhibition_hours
|
||||||
|
WHERE id NOT IN (
|
||||||
|
SELECT MAX(id)
|
||||||
|
FROM user_exhibition_hours
|
||||||
|
WHERE source_id LIKE 'exhibition_%'
|
||||||
|
GROUP BY user_id, star_id, source_id
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 添加去重逻辑(可选增强)
|
||||||
|
|
||||||
|
在 `AddExhibitionHours` 中使用 `source_id` 进行去重:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *fanProfileRepository) AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) {
|
||||||
|
// 检查是否已处理过此 source
|
||||||
|
var existing fanProfile
|
||||||
|
err := r.db.Where("user_id = ? AND star_id = ? AND exhibition_source_id = ?", userID, starID, sourceID).First(&existing).Error
|
||||||
|
if err == nil {
|
||||||
|
// 已存在,跳过(幂等性保证)
|
||||||
|
return existing.Level, 0, 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... 正常逻辑 ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、验证步骤
|
||||||
|
|
||||||
|
### 4.1 代码验证
|
||||||
|
|
||||||
|
1. ✅ 确认 `cleanup_worker.go` 文件存在于 `service/` 目录
|
||||||
|
2. ✅ 确认 `GetExpiredExhibitions` 方法签名正确(接收 `int64` 时间戳)
|
||||||
|
3. ✅ 确认 CleanupWorker 调用 `taskClient.OnExhibitionCompleted()`
|
||||||
|
4. ✅ 确认 `revenue_service.go` 中 `OnExhibitionCompleted` 调用 `AddExhibitionHours`
|
||||||
|
5. ✅ 确认 `main.go` 和 `NewRevenueService` 签名匹配
|
||||||
|
|
||||||
|
### 4.2 功能验证
|
||||||
|
|
||||||
|
1. 启动 galleryService
|
||||||
|
2. 创建一个过期的展品(expire_at < NOW())
|
||||||
|
3. 等待 CleanupWorker 执行(1分钟内)
|
||||||
|
4. 检查 logs 中是否有 "CleanupWorker: processing expired exhibitions"
|
||||||
|
5. 检查 `exhibition_revenue_records` 表是否有新记录
|
||||||
|
6. 检查 `user_exhibition_hours` 表是否有对应的时长记录
|
||||||
|
|
||||||
|
### 4.3 去重验证
|
||||||
|
|
||||||
|
1. 多次触发同一展品的 OnExhibitionCompleted
|
||||||
|
2. 确认 `user_exhibition_hours` 中只有一条记录
|
||||||
|
3. 确认累计时长正确(不应累加多次)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、风险与注意事项
|
||||||
|
|
||||||
|
1. **幂等性**: OnExhibitionCompleted 必须是幂等的,重复调用不应产生重复数据
|
||||||
|
2. **事务性**: AddExhibitionHours 和 revenue record 创建应该在同一事务中(当前未实现,需要评估)
|
||||||
|
3. **时区问题**: 使用 Asia/Shanghai 时区计算时长
|
||||||
|
4. **历史数据**: 修复前的历史重复数据需要手动清理
|
||||||
|
5. **编译验证**: 修改后需重新编译 `go build ./services/galleryService/...` 和 `go build ./services/taskService/...`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、文件清单
|
||||||
|
|
||||||
|
| 文件路径 | 操作 | 关键修改 |
|
||||||
|
|----------|------|----------|
|
||||||
|
| `backend/services/galleryService/service/cleanup_worker.go` | **新增** | 完整实现 CleanupWorker,调用 taskClient.OnExhibitionCompleted |
|
||||||
|
| `backend/services/taskService/service/revenue_service.go` | 修改 | OnExhibitionCompleted 中添加 AddExhibitionHours 调用 |
|
||||||
|
| `backend/services/taskService/main.go` | 修改 | 修复 NewRevenueService 调用签名 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、修复后数据流
|
||||||
|
|
||||||
|
```
|
||||||
|
正确的数据流:
|
||||||
|
|
||||||
|
展位过期 (expire_at < NOW())
|
||||||
|
↓
|
||||||
|
CleanupWorker.Start() 每分钟扫描
|
||||||
|
↓
|
||||||
|
GetExpiredExhibitions() 获取过期展品
|
||||||
|
↓
|
||||||
|
对每个展品调用 processExpiredExhibition()
|
||||||
|
↓
|
||||||
|
taskClient.OnExhibitionCompleted() RPC 调用 ← 缺失的调用
|
||||||
|
↓
|
||||||
|
TaskInternalProvider.OnExhibitionCompleted()
|
||||||
|
↓
|
||||||
|
revenueService.OnExhibitionCompleted()
|
||||||
|
├── 创建 revenue record (slot_owner 获取收益)
|
||||||
|
└── userClient.AddExhibitionHours() (slot_owner 累加上架时长) ← 缺失的调用
|
||||||
|
↓
|
||||||
|
repo.DeleteExhibition() 软删除展品
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附:待确认 - main.go 调用签名不匹配
|
||||||
|
|
||||||
|
### 现象
|
||||||
|
```bash
|
||||||
|
$ grep "NewRevenueService" backend/services/taskService/main.go
|
||||||
|
→ revenueSvc := service.NewRevenueService(revenueRepo, userRPCClient, galleryRPCClient)
|
||||||
|
# 传3个参数
|
||||||
|
|
||||||
|
$ grep "func NewRevenueService" backend/services/taskService/service/revenue_service.go
|
||||||
|
→ func NewRevenueService(revenueRepo repository.RevenueRepository, userClient client.UserServiceClient) RevenueService {
|
||||||
|
# 只接收2个参数
|
||||||
|
```
|
||||||
|
|
||||||
|
### 验证方法
|
||||||
|
```bash
|
||||||
|
cd backend && go build ./services/taskService/...
|
||||||
|
```
|
||||||
|
如果编译报错,说明确实是签名不匹配问题。
|
||||||
|
|
||||||
|
### 可能原因
|
||||||
|
1. **代码未同步** - main.go 或 revenue_service.go 有过修改但另一处未同步
|
||||||
|
2. **存在另一个定义** - 如果编译通过,可能有其他地方定义了 NewRevenueService
|
||||||
|
|
||||||
|
### 搜索结果
|
||||||
|
全项目搜索只找到一个定义:`backend/services/taskService/service/revenue_service.go:26`
|
||||||
|
|
||||||
|
这表明 **main.go 存在编译错误**,需要将 `galleryRPCClient` 移除或修改函数签名。
|
||||||
Loading…
Reference in New Issue
Block a user