mirror of
https://github.com/yyhuni/xingrin.git
synced 2026-01-31 19:53:11 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5de7ea9dbc | ||
|
|
971641cdeb | ||
|
|
e5a74faf9f |
8
.github/workflows/docker-build.yml
vendored
8
.github/workflows/docker-build.yml
vendored
@@ -100,8 +100,12 @@ jobs:
|
||||
tags: |
|
||||
${{ env.IMAGE_PREFIX }}/${{ matrix.image }}:${{ steps.version.outputs.VERSION }}
|
||||
${{ steps.version.outputs.IS_RELEASE == 'true' && format('{0}/{1}:latest', env.IMAGE_PREFIX, matrix.image) || '' }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
cache-from: |
|
||||
type=gha
|
||||
type=registry,ref=${{ env.IMAGE_PREFIX }}/${{ matrix.image }}:buildcache
|
||||
cache-to: |
|
||||
type=gha,mode=max
|
||||
type=registry,ref=${{ env.IMAGE_PREFIX }}/${{ matrix.image }}:buildcache,mode=max
|
||||
|
||||
# 所有镜像构建成功后,更新 VERSION 文件
|
||||
update-version:
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
trigger: always_on
|
||||
---
|
||||
|
||||
1.后端网页应该是 8888 端口
|
||||
3.前端所有路由加上末尾斜杠,以匹配 django 的 DRF 规则
|
||||
4.网页测试可以用 curl
|
||||
8.所有前端 api 接口都应该写在@services 中,所有 type 类型都应该写在@types 中
|
||||
10.前端的加载等逻辑用 React Query来实现,自动管理
|
||||
17.所有业务操作的 toast 都放在 hook 中
|
||||
23.前端非必要不要采用window.location.href去跳转,而是用Next.js 客户端路由
|
||||
24.ui相关的都去调用mcp来看看有没有通用组件,美观的组件来实现
|
||||
@@ -1,85 +0,0 @@
|
||||
---
|
||||
trigger: manual
|
||||
description: 进行代码审查的时候,必须调用这个规则
|
||||
---
|
||||
|
||||
### **0. 逻辑正确性 & Bug 排查** *(最高优先级,必须手动推演)*
|
||||
|
||||
**目标**:不依赖测试,主动发现“代码能跑但结果错”的逻辑错误。
|
||||
|
||||
1. **手动推演关键路径**:
|
||||
- 选 2~3 个典型输入(含边界),**在脑中或纸上一步步推演代码执行流程**。
|
||||
- 输出是否符合预期?每一步变量变化是否正确?
|
||||
2. **常见逻辑 bug 检查**:
|
||||
- **off-by-one**:循环、数组索引、分页
|
||||
- **条件逻辑错误**:`and`/`or` 优先级、短路求值误用
|
||||
- **状态混乱**:变量未初始化、被意外覆盖
|
||||
- **算法偏差**:排序、搜索、二分查找的中点处理
|
||||
- **浮点精度**:是否误用 `==` 比较浮点数?
|
||||
3. **控制流审查**:
|
||||
- 所有 `if/else` 分支是否都覆盖?有无“不可达代码”?
|
||||
- `switch`/`match` 是否有 `default`?是否漏 case?
|
||||
- 异常路径会返回什么?是否遗漏 `finally` 清理?
|
||||
4. **业务逻辑一致性**:
|
||||
- 是否符合**业务规则**?(如“订单总额 = 商品价 × 数量 + 运费 - 折扣”)
|
||||
- 是否遗漏隐含约束?(如“用户只能评价已完成的订单”)
|
||||
|
||||
### **一、功能性 & 正确性** *(阻塞性问题必须修复)*
|
||||
|
||||
1. **需求符合度**:是否100%覆盖需求?遗漏/多余功能点?
|
||||
2. **边界条件**:
|
||||
- 输入:`null`、空、极值、非法格式
|
||||
- 集合:空、单元素、超大(如10⁶)
|
||||
- 循环:终止条件、off-by-one
|
||||
3. **错误处理**:
|
||||
- 异常捕获全面?失败路径有降级?
|
||||
- 错误信息清晰?不泄露栈迹?
|
||||
4. **并发安全**:
|
||||
- 竞态/死锁风险?共享资源是否同步?
|
||||
- 使用了`volatile`/`synchronized`/`Lock`/`atomic`?
|
||||
5. **单元测试**:
|
||||
- 覆盖率 ≥80%?包含正向/边界/异常用例?
|
||||
- 测试独立?无外部依赖?
|
||||
|
||||
### **二、代码质量与可读性**
|
||||
|
||||
1. **命名**:见名知意?遵循规范?
|
||||
2. **函数设计**:
|
||||
- **单一职责**?参数 ≤4?建议长度 <50行(视语言调整)
|
||||
- 可提取为工具函数?
|
||||
3. **结构与复杂度**:
|
||||
- 无重复代码?圈复杂度 <10?
|
||||
- 嵌套 ≤3层?使用卫语句提前返回
|
||||
4. **注释**:解释**为什么**而非**是什么**?复杂逻辑必注释
|
||||
5. **风格一致**:通过`Prettier`/`ESLint`/`Spotless`自动格式化
|
||||
|
||||
### **三、架构与设计**
|
||||
|
||||
1. **SOLID**:是否符合单一职责、开闭、依赖倒置?
|
||||
2. **依赖**:是否依赖接口而非实现?无循环依赖?
|
||||
3. **可测试性**:是否支持依赖注入?避免`new`硬编码
|
||||
4. **扩展性**:新增功能是否只需改一处?
|
||||
|
||||
### **四、性能优化**
|
||||
|
||||
- **N+1查询**?循环内IO/日志/分配?
|
||||
- 算法复杂度合理?(如O(n²)是否可优化)
|
||||
- 内存:无泄漏?大对象及时释放?缓存有失效?
|
||||
|
||||
### **五、其他**
|
||||
|
||||
1. **可维护性**:日志带上下文?修改后更干净?
|
||||
2. **兼容性**:API/数据库变更是否向后兼容?
|
||||
3. **依赖管理**:新库必要?许可证合规?
|
||||
|
||||
---
|
||||
|
||||
### **审查最佳实践**
|
||||
|
||||
- **小批次审查**:≤200行/次
|
||||
- **语气建议**:`“建议将函数拆分以提升可读性”` 而非 `“这个函数太长了”`
|
||||
- **自动化先行**:风格/空指针/安全扫描 → CI工具
|
||||
- **重点分级**:
|
||||
- 🛑 **阻塞**:功能错、安全漏洞
|
||||
- ⚠️ **必须改**:设计缺陷、性能瓶颈
|
||||
- 💡 **建议**:风格、命名、可读性
|
||||
@@ -1,195 +0,0 @@
|
||||
---
|
||||
trigger: always_on
|
||||
---
|
||||
|
||||
## 标准分层架构调用顺序
|
||||
|
||||
按照 **DDD(领域驱动设计)和清洁架构**原则,调用顺序应该是:
|
||||
|
||||
```
|
||||
HTTP请求 → Views → Tasks → Services → Repositories → Models
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 📊 完整的调用链路图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HTTP Request (前端) │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Views (HTTP 层) │
|
||||
│ - 参数验证 │
|
||||
│ - 权限检查 │
|
||||
│ - 调用 Tasks/Services │
|
||||
│ - 返回 HTTP 响应 │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
↓
|
||||
┌────────────────┴────────────────┐
|
||||
↓ (异步) ↓ (同步)
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Tasks (任务层) │ │ Services (业务层)│
|
||||
│ - 异步执行 │ │ - 业务逻辑 │
|
||||
│ - 后台作业 │───────>│ - 事务管理 │
|
||||
│ - 通知发送 │ │ - 数据验证 │
|
||||
└──────────────────┘ └────────┬─────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ Repositories (存储层) │
|
||||
│ - 数据访问 │
|
||||
│ - 查询封装 │
|
||||
│ - 批量操作 │
|
||||
└────────┬─────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ Models (模型层) │
|
||||
│ - ORM 定义 │
|
||||
│ - 数据结构 │
|
||||
│ - 关系映射 │
|
||||
└──────────────────────┘
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔄 具体调用示例
|
||||
|
||||
### **场景 1:同步删除(Views → Services → Repositories → Models)**
|
||||
|
||||
```python
|
||||
# 1. Views 层 (views.py)
|
||||
def some_sync_delete(self, request):
|
||||
# 参数验证
|
||||
target_ids = request.data.get('ids')
|
||||
|
||||
# 调用 Service 层
|
||||
service = TargetService()
|
||||
result = service.bulk_delete_targets(target_ids)
|
||||
|
||||
# 返回响应
|
||||
return Response({'message': 'deleted'})
|
||||
|
||||
# 2. Services 层 (services/target_service.py)
|
||||
class TargetService:
|
||||
def bulk_delete_targets(self, target_ids):
|
||||
# 业务逻辑验证
|
||||
logger.info("准备删除...")
|
||||
|
||||
# 调用 Repository 层
|
||||
deleted_count = self.repo.bulk_delete_by_ids(target_ids)
|
||||
|
||||
# 返回结果
|
||||
return deleted_count
|
||||
|
||||
# 3. Repositories 层 (repositories/django_target_repository.py)
|
||||
class DjangoTargetRepository:
|
||||
def bulk_delete_by_ids(self, target_ids):
|
||||
# 数据访问操作
|
||||
return Target.objects.filter(id__in=target_ids).delete()
|
||||
|
||||
# 4. Models 层 (models.py)
|
||||
class Target(models.Model):
|
||||
# ORM 定义
|
||||
name = models.CharField(...)
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **场景 2:异步删除(Views → Tasks → Services → Repositories → Models)**
|
||||
|
||||
```python
|
||||
# 1. Views 层 (views.py)
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
target = self.get_object()
|
||||
|
||||
# 调用 Tasks 层(异步)
|
||||
async_bulk_delete_targets([target.id], [target.name])
|
||||
|
||||
# 立即返回 202
|
||||
return Response(status=202)
|
||||
|
||||
# 2. Tasks 层 (tasks/target_tasks.py)
|
||||
def async_bulk_delete_targets(target_ids, target_names):
|
||||
def _delete():
|
||||
# 发送通知
|
||||
create_notification("删除中...")
|
||||
|
||||
# 调用 Service 层
|
||||
service = TargetService()
|
||||
result = service.bulk_delete_targets(target_ids)
|
||||
|
||||
# 发送完成通知
|
||||
create_notification("删除成功")
|
||||
|
||||
# 后台线程执行
|
||||
threading.Thread(target=_delete).start()
|
||||
|
||||
# 3. Services 层 (services/target_service.py)
|
||||
class TargetService:
|
||||
def bulk_delete_targets(self, target_ids):
|
||||
# 业务逻辑
|
||||
return self.repo.bulk_delete_by_ids(target_ids)
|
||||
|
||||
# 4. Repositories 层 (repositories/django_target_repository.py)
|
||||
class DjangoTargetRepository:
|
||||
def bulk_delete_by_ids(self, target_ids):
|
||||
# 数据访问
|
||||
return Target.objects.filter(id__in=target_ids).delete()
|
||||
|
||||
# 5. Models 层 (models.py)
|
||||
class Target(models.Model):
|
||||
# ORM 定义
|
||||
...
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 📋 各层职责清单
|
||||
|
||||
| 层级 | 职责 | 不应该做 |
|
||||
| --- | --- | --- |
|
||||
| **Views** | HTTP 请求处理、参数验证、权限检查 | ❌ 直接访问 Models<br>❌ 业务逻辑 |
|
||||
| **Tasks** | 异步执行、后台作业、通知发送 | ❌ 直接访问 Models<br>❌ HTTP 响应 |
|
||||
| **Services** | 业务逻辑、事务管理、数据验证 | ❌ 直接写 SQL<br>❌ HTTP 相关 |
|
||||
| **Repositories** | 数据访问、查询封装、批量操作 | ❌ 业务逻辑<br>❌ 通知发送 |
|
||||
| **Models** | ORM 定义、数据结构、关系映射 | ❌ 业务逻辑<br>❌ 复杂查询 |
|
||||
|
||||
---
|
||||
|
||||
### ✅ 最佳实践原则
|
||||
|
||||
1. **单向依赖**:只能向下调用,不能向上调用
|
||||
|
||||
```
|
||||
Views → Tasks → Services → Repositories → Models
|
||||
(上层) (下层)
|
||||
|
||||
```
|
||||
|
||||
2. **层级隔离**:相邻层交互,禁止跨层
|
||||
- ✅ Views → Services
|
||||
- ✅ Tasks → Services
|
||||
- ✅ Services → Repositories
|
||||
- ❌ Views → Repositories(跨层)
|
||||
- ❌ Tasks → Models(跨层)
|
||||
3. **依赖注入**:通过构造函数注入依赖
|
||||
|
||||
```python
|
||||
class TargetService:
|
||||
def __init__(self):
|
||||
self.repo = DjangoTargetRepository() # 注入
|
||||
|
||||
```
|
||||
|
||||
4. **接口抽象**:使用 Protocol 定义接口
|
||||
|
||||
```python
|
||||
class TargetRepository(Protocol):
|
||||
def bulk_delete_by_ids(self, ids): ...
|
||||
|
||||
```
|
||||
@@ -106,7 +106,7 @@ services:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/worker/Dockerfile
|
||||
image: docker-worker:latest
|
||||
image: docker-worker:${IMAGE_TAG:-latest}-dev
|
||||
restart: "no"
|
||||
volumes:
|
||||
- /opt/xingrin/results:/app/backend/results
|
||||
|
||||
@@ -152,13 +152,13 @@ sequenceDiagram
|
||||
|
||||
### 本地开发测试
|
||||
```bash
|
||||
# docker/.env 中添加
|
||||
TASK_EXECUTOR_IMAGE=docker-agent:latest # 指向本地构建镜像
|
||||
# docker/.env 中添加(开发模式会自动设置)
|
||||
TASK_EXECUTOR_IMAGE=docker-worker:v1.1.0-dev # 指向本地构建镜像
|
||||
```
|
||||
|
||||
### 开发模式启动
|
||||
```bash
|
||||
# 使用本地构建镜像
|
||||
# 使用本地构建镜像(自动构建并标记为 ${VERSION}-dev)
|
||||
./install.sh --dev
|
||||
./start.sh --dev
|
||||
```
|
||||
@@ -238,7 +238,8 @@ curl -s https://hub.docker.com/v2/repositories/yyhuni/xingrin-worker/tags/
|
||||
4. ✅ 使用 `docker system prune` 清理旧镜像
|
||||
|
||||
### 开发调试
|
||||
1. ✅ 本地测试使用 `--dev` 模式
|
||||
1. ✅ 本地测试使用 `--dev` 模式(自动构建 `docker-worker:${VERSION}-dev`)
|
||||
2. ✅ 远程测试先推送测试版本到 Hub
|
||||
3. ✅ 生产环境避免使用 `latest` 标签
|
||||
4. ✅ 版本回滚通过修改 `IMAGE_TAG` 实现
|
||||
3. ✅ 生产环境避免使用 `latest` 标签,始终使用明确版本号
|
||||
4. ✅ 开发环境使用 `-dev` 后缀区分开发版本
|
||||
5. ✅ 版本回滚通过修改 `IMAGE_TAG` 实现
|
||||
21
install.sh
21
install.sh
@@ -404,24 +404,23 @@ WORKER_IMAGE="${DOCKER_USER}/xingrin-worker:${APP_VERSION}"
|
||||
if [ "$DEV_MODE" = true ]; then
|
||||
info "开发模式:构建本地 Worker 镜像..."
|
||||
if docker compose -f "$DOCKER_DIR/docker-compose.dev.yml" build worker; then
|
||||
# 设置 TASK_EXECUTOR_IMAGE 环境变量指向本地构建的镜像
|
||||
update_env_var "$DOCKER_DIR/.env" "TASK_EXECUTOR_IMAGE" "docker-worker:latest"
|
||||
success "本地 Worker 镜像构建完成,并设置为默认使用镜像"
|
||||
# 设置 TASK_EXECUTOR_IMAGE 环境变量指向本地构建的镜像(使用版本号-dev标识)
|
||||
update_env_var "$DOCKER_DIR/.env" "TASK_EXECUTOR_IMAGE" "docker-worker:${APP_VERSION}-dev"
|
||||
success "本地 Worker 镜像构建完成: docker-worker:${APP_VERSION}-dev"
|
||||
else
|
||||
warn "本地 Worker 镜像构建失败,将使用远程镜像"
|
||||
info "正在拉取: $WORKER_IMAGE"
|
||||
if docker pull "$WORKER_IMAGE"; then
|
||||
success "Worker 镜像拉取完成"
|
||||
else
|
||||
warn "Worker 镜像拉取失败,扫描时会自动重试拉取"
|
||||
fi
|
||||
error "开发模式下本地 Worker 镜像构建失败!"
|
||||
error "请检查构建错误并修复后重试"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
info "正在拉取: $WORKER_IMAGE"
|
||||
if docker pull "$WORKER_IMAGE"; then
|
||||
success "Worker 镜像拉取完成"
|
||||
else
|
||||
warn "Worker 镜像拉取失败,扫描时会自动重试拉取"
|
||||
error "Worker 镜像拉取失败,无法继续安装"
|
||||
error "请检查网络连接或 Docker Hub 访问权限"
|
||||
error "镜像地址: $WORKER_IMAGE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user