JobData/.claude/plan/ruff-optimization.md
2026-03-22 23:22:30 +08:00

214 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 📋 实施计划Ruff 代码优化 + 项目质量提升
> 生成时间2026-03-20
> 工作目录:/Users/win/2025/AICoding/JobData
---
## 一、现状问题总览
### 1.1 Ruff 实际扫描结果34 个错误22 个可自动修复)
| 规则 | 数量 | 说明 | 可自动修复 |
|------|------|------|:---:|
| `F401` | 20 | 未使用的 import | ✅ |
| `E402` | 5 | import 不在文件顶部 | ❌ |
| `F541` | 3 | f-string 没有占位符 | ✅ |
| `F821` | 3 | 引用了未定义的变量名 | ❌ |
| `F811` | 2 | 重复定义(导入后又被覆盖) | ✅ |
| `E722` | 1 | 裸 `except:`(不捕获具体异常) | ❌ |
| **合计** | **34** | | **22 可自动修复** |
### 1.2 受影响文件清单
| 文件 | 问题数 | 最严重问题 |
|------|--------|-----------|
| `app/api/v1/token/token.py` | 8 | E402 + F811import 顺序混乱,重复定义) |
| `app/services/job.py` | 3 | **F821 未定义变量** `udt``fpt`**E722 裸 except** |
| `app/services/crawler/zhilian.py` | 1 | **F821 未定义变量** `json` |
| `app/services/company_cleaner.py` | 3 | F541 空 f-string |
| `app/services/crawler/__init__.py` | 3 | F401 无效的服务导出 |
| `app/repositories/clickhouse_repo.py` | 2 | F401 `math`, `Generator` |
| `app/schemas/token.py` | 2 | F401 `Dict`, `Any` |
| `app/controllers/job.py` | 1 | F401 `Optional` |
| `app/controllers/keyword.py` | 1 | F401 `CRUDBase` |
| `app/core/algorithms/antispider.py` | 1 | F401 `os` |
| `app/core/ip_tracking.py` | 1 | F401 `Any` |
| `app/core/locks.py` | 1 | F401 `time` |
| `app/api/v1/analytics.py` | 1 | F401 `List` |
| `app/api/v1/ingest/ingest.py` | 1 | F401 `Optional` |
| `app/schemas/analytics.py` | 1 | F401 `Any` |
| `app/services/crawler/boss.py` | 1 | F401 `os` |
---
### 1.3 Ruff 扫描之外的深层问题(代码审查发现)
#### 🔴 CRITICAL — 安全问题(硬编码凭据)
| 文件 | 行号 | 问题 |
|------|------|------|
| `app/settings/config.py` | ~23 | `SECRET_KEY = "CHANGE_ME_DEV_ONLY"` JWT 密钥 |
| `app/settings/config.py` | ~27-30 | ClickHouse 主机 IP、用户名、密码明文 |
| `app/settings/config.py` | ~44-45 | SMTP 真实邮箱账号 + 授权码明文 |
| `app/settings/config.py` | ~52 | MySQL root 密码 + 生产 IP 硬编码在连接串 |
| `app/services/job.py` | ~533-535 | 外部 API salt 硬编码 |
#### 🔴 HIGH — 性能问题(事件循环阻塞)
| 文件 | 行号 | 问题 |
|------|------|------|
| `app/services/job.py` | ~547 | `async def` 中调用同步 `requests.post` 阻塞事件循环 |
| `app/services/job.py` | ~926-933 | 串行逐条发送远程推送N 条数据 = N 次串行阻塞 |
| `app/core/locks.py` | ~38 | 同步 `redis.Redis``async` 方法中调用,阻塞事件循环 |
#### 🟡 MEDIUM — 代码质量
| 文件 | 问题 |
|------|------|
| `app/services/job.py` | 7 个 `_check_*_duplicate` 方法几乎完全重复,仅 SQL 参数不同 |
| `app/services/job.py` | 1 个死代码方法:`_check_qcwy_company_duplicate_by_name` 从未被调用 |
| `app/repositories/clickhouse_repo.py` | `group_by_column` 直接拼入 SQL潜在 SQL 注入) |
| `app/api/v1/__init__.py` | 同一 router 注册两次(`/job``/universal`OpenAPI 文档重复 |
| 全项目 | 零测试文件,关键业务逻辑(去重、路由分发)无任何测试保护 |
---
## 二、实施步骤
### Phase 1Ruff 自动修复低风险5 分钟)
```bash
# 自动修复 22 个可自动修复的问题
pipenv run ruff check app/ --fix
# 验证修复结果
pipenv run ruff check app/ --statistics
```
自动修复覆盖F401未使用 import、F541空 f-string、F811重复定义
### Phase 2手动修复 Ruff 报告的无法自动修复问题12 个)
#### 2.1 F821 未定义变量CRITICAL会导致运行时崩溃
**`app/services/job.py:348`** — 变量 `udt` 未定义
需要读取上下文,确认 `udt` 应该是什么(可能是 `update_date_time` 的缩写或某个局部变量)。
**`app/services/job.py:374`** — 变量 `fpt` 未定义
需要读取上下文,确认 `fpt` 应该是什么(可能是 `first_publish_time` 缩写)。
**`app/services/crawler/zhilian.py:60`** — `json` 模块未导入但被使用
修复:在文件顶部添加 `import json`
#### 2.2 E722 裸 except`app/services/job.py:302`
```python
# 修改前
except:
pass
# 修改后
except Exception as e:
logger.error(f"处理失败: {e}")
```
#### 2.3 E402 import 不在顶部(`app/api/v1/token/token.py:92-96`
将条件式 import 移至文件顶部,或使用 `TYPE_CHECKING` 保护块。
### Phase 3凭据安全CRITICAL建议本次一并完成
**目标**:将所有硬编码凭据移入环境变量
1. 在项目根目录创建 `.env.example`(安全模板)
2. 修改 `app/settings/config.py`,用 `pydantic-settings` 从环境变量读取所有敏感值
3. 启动时校验必填环境变量缺失则报错退出Fail Fast
4.`.env` 加入 `.gitignore`(已有则确认)
```python
# config.py 改造后示例
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
SECRET_KEY: str # 必填,无默认值
CLICKHOUSE_HOST: str = "localhost"
CLICKHOUSE_USER: str = "default"
CLICKHOUSE_PASS: str # 必填
SMTP_USER: str = ""
SMTP_PASS: str = ""
DB_URL: str # 必填
class Config:
env_file = ".env"
```
### Phase 4性能修复async 阻塞问题)
1.`app/services/job.py` 中的 `requests.post` 替换为 `httpx.AsyncClient`(已在依赖中)
2.`_batch_send_to_remote_server` 改为 `asyncio.gather` 并发执行
3.`app/core/locks.py` 中的同步 `redis.Redis` 替换为 `aioredis`(或 `redis.asyncio`
### Phase 5代码去重可维护性
合并 7 个重复的 `_check_*_duplicate` 方法为 1 个通用方法:
```python
async def _check_duplicate(
self,
table: str,
conditions: dict[str, str], # {"column_name": "value"}
days: int = 90
) -> bool:
...
```
删除死代码:`_check_qcwy_company_duplicate_by_name`
---
## 三、关键文件索引
| 文件 | 操作 | 说明 |
|------|------|------|
| `app/settings/config.py` | 重构 | 凭据移入环境变量 |
| `app/services/job.py` | 修复 | F821、E722、async 阻塞、方法去重 |
| `app/services/crawler/zhilian.py` | 修复 | 添加 `import json` |
| `app/api/v1/token/token.py` | 整理 | 修复 E402 import 顺序 |
| `app/services/company_cleaner.py` | 自动修复 | F541 空 f-string |
| `app/core/locks.py` | 修复 | 同步 redis → 异步 |
| `app/repositories/clickhouse_repo.py` | 修复 | 删除未用 import |
| `.env.example` | 新建 | 环境变量模板 |
---
## 四、风险与缓解
| 风险 | 缓解措施 |
|------|----------|
| 修复 F821 时误判变量用途 | 先读原函数完整逻辑再修复 |
| 凭据迁移后服务无法启动 | 先创建 `.env` 再重启服务 |
| async 改造引入新 bug | 修改后在本地运行完整功能测试 |
| 方法合并破坏去重逻辑 | 保持原有 SQL 逻辑不变,只提取公共参数 |
---
## 五、执行顺序建议
```
Phase 15min → pipenv run ruff check app/ --fix
Phase 230min → 手动修复 F821 × 3、E722 × 1、E402 × 5
Phase 360min → 凭据安全迁移(需配合运维创建 .env
Phase 490min → async 阻塞修复requests → httpx
Phase 560min → 去重方法合并(可选,不影响功能)
```
---
## SESSION_ID供 /ccg:execute 使用)
- CODEX_SESSION: N/A本次分析由 Claude 本地执行)
- GEMINI_SESSION: N/A