create-dwy 0.8.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/create.js +50 -3
- package/src/utils.js +8 -0
- package/templates/claude-global/CLAUDE.md +81 -6
- package/templates/claude-global/rules/dwy-postgres.md +89 -0
- package/templates/claude-global/rules/dwy-python-backend.md +492 -0
- package/templates/claude-global/rules/dwy-python-core.md +94 -634
- package/templates/claude-global/rules/dwy-python-testing.md +115 -13
- package/templates/claude-global/rules/dwy-redis.md +88 -0
- package/templates/claude-global/rules/dwy-vue-core.md +341 -645
- package/templates/claude-global/rules/dwy-vue-pinia.md +47 -34
- package/templates/claude-global/rules/dwy-vue-testing.md +120 -55
- package/templates/claude-global/skills/dwy-deploy-audit/references/checks-network.md +1 -1
- package/templates/claude-global/skills/dwy-deploy-audit/scripts/check_nginx.sh +1 -1
- package/templates/claude-global/skills/dwy-dolphindb/SKILL.md +22 -15
- package/templates/claude-global/skills/dwy-dolphindb/evals/evals.json +23 -0
- package/templates/claude-global/skills/dwy-dolphindb/references/dolphindb-rules.md +100 -1
- package/templates/claude-global/skills/dwy-ekit/SKILL.md +142 -276
- package/templates/claude-global/skills/dwy-eui/SKILL.md +264 -182
- package/templates/claude-global/skills/dwy-fullstack-scaffold/SKILL.md +117 -129
- package/templates/claude-global/skills/dwy-git-commit/SKILL.md +125 -0
- package/templates/claude-global/skills/dwy-publish/SKILL.md +1 -1
- package/templates/claude-global/{rules/dwy-tech-stack.md → skills/dwy-tech-stack/SKILL.md} +4 -3
- package/templates/project/fullstack-monorepo/CLAUDE.md.hbs +81 -0
- package/templates/project/fullstack-monorepo/_env.example.hbs +24 -0
- package/templates/project/fullstack-monorepo/_gitignore +37 -0
- package/templates/project/fullstack-monorepo/backend/.python-version +1 -0
- package/templates/project/fullstack-monorepo/backend/CLAUDE.md.hbs +68 -0
- package/templates/project/fullstack-monorepo/backend/Dockerfile.dev +23 -0
- package/templates/project/fullstack-monorepo/backend/alembic/env.py.hbs +68 -0
- package/templates/project/fullstack-monorepo/backend/alembic/script.py.mako +26 -0
- package/templates/project/fullstack-monorepo/backend/alembic.ini.hbs +43 -0
- package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/pyproject.toml +16 -0
- package/templates/project/fullstack-monorepo/backend/packages/dwy-shared/src/dwy_shared/__init__.py +12 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/pyproject.toml.hbs +20 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/__init__.py.hbs +40 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/config.py +9 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/models.py.hbs +17 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/protocols.py +14 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/router.py.hbs +22 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/schemas.py +21 -0
- package/templates/project/fullstack-monorepo/backend/packages/{{scopePrefix}}-{{initialDomain}}/src/{{scopePrefix}}_{{initialDomain}}/service.py +11 -0
- package/templates/project/fullstack-monorepo/backend/pyproject.toml.hbs +84 -0
- package/templates/project/fullstack-monorepo/backend/src/app/__init__.py +3 -0
- package/templates/project/fullstack-monorepo/backend/src/app/config.py.hbs +21 -0
- package/templates/project/fullstack-monorepo/backend/src/app/exceptions.py +26 -0
- package/templates/project/fullstack-monorepo/backend/src/app/factories.py +16 -0
- package/templates/project/fullstack-monorepo/backend/src/app/infra/__init__.py +1 -0
- package/templates/project/fullstack-monorepo/backend/src/app/main.py.hbs +65 -0
- package/templates/project/fullstack-monorepo/backend/src/app/middleware/__init__.py +1 -0
- package/templates/project/fullstack-monorepo/backend/tests/__init__.py +0 -0
- package/templates/project/fullstack-monorepo/backend/tests/conftest.py.hbs +42 -0
- package/templates/project/fullstack-monorepo/dev.sh.hbs +83 -0
- package/templates/project/fullstack-monorepo/docker-compose.dev.yml.hbs +36 -0
- package/templates/project/fullstack-monorepo/frontend/CLAUDE.md.hbs +35 -0
- package/templates/project/fullstack-monorepo/frontend/Dockerfile +18 -0
- package/templates/project/fullstack-monorepo/frontend/_npmrc +3 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/index.html.hbs +13 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/package.json.hbs +31 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/App.vue.hbs +10 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/api/client.ts.hbs +11 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/features/{{initialDomain}}/.gitkeep +0 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/index.css +12 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/main.ts +17 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/router/index.ts.hbs +24 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/stores/.gitkeep +0 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/types/.gitkeep +0 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/src/views/HomeView.vue.hbs +36 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/tsconfig.json +7 -0
- package/templates/project/fullstack-monorepo/frontend/apps/web/vite.config.ts.hbs +27 -0
- package/templates/project/fullstack-monorepo/frontend/nginx.conf +11 -0
- package/templates/project/fullstack-monorepo/frontend/package.json.hbs +13 -0
- package/templates/project/fullstack-monorepo/frontend/packages/core/package.json.hbs +15 -0
- package/templates/project/fullstack-monorepo/frontend/packages/core/src/index.ts +3 -0
- package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/package.json.hbs +14 -0
- package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/index.ts.hbs +16 -0
- package/templates/project/fullstack-monorepo/frontend/packages/features/{{initialDomain}}/src/pages/IndexPage.vue.hbs +9 -0
- package/templates/project/fullstack-monorepo/frontend/packages/ui/package.json.hbs +15 -0
- package/templates/project/fullstack-monorepo/frontend/packages/ui/src/index.ts +3 -0
- package/templates/project/fullstack-monorepo/frontend/pnpm-workspace.yaml.hbs +23 -0
- package/templates/project/fullstack-monorepo/frontend/tsconfig.base.json.hbs +23 -0
- package/templates/claude-global/rules/dwy-api-design.md +0 -110
- package/templates/claude-global/rules/dwy-git-commit-convention.md +0 -82
- package/templates/claude-global/rules/dwy-git-security.md +0 -53
- package/templates/claude-global/rules/dwy-payload-limits.md +0 -186
- package/templates/claude-global/rules/dwy-prefer-open-source.md +0 -32
- package/templates/claude-global/rules/dwy-project-structure.md +0 -181
- package/templates/claude-global/rules/dwy-python-fastapi.md +0 -272
- package/templates/claude-global/rules/dwy-python-orm.md +0 -61
- package/templates/claude-global/rules/dwy-python-security.md +0 -636
- package/templates/claude-global/rules/dwy-server-security.md +0 -518
- package/templates/claude-global/rules/dwy-vue-api.md +0 -146
- package/templates/claude-global/skills/dwy-ekit/references/data.md +0 -135
- package/templates/claude-global/skills/dwy-ekit/references/form.md +0 -68
- package/templates/claude-global/skills/dwy-ekit/references/request.md +0 -183
- package/templates/claude-global/skills/dwy-ekit/references/ui.md +0 -109
- package/templates/claude-global/skills/dwy-vue-core/SKILL.md +0 -890
- /package/templates/{claude-global/commands → project/fullstack-monorepo/backend/alembic/versions}/.gitkeep +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Python pytest
|
|
2
|
+
description: Python pytest 测试规范(目录组织、fixture、异步、AAA 结构)
|
|
3
3
|
paths:
|
|
4
4
|
- "**/tests/**/*.py"
|
|
5
5
|
- "**/test_*.py"
|
|
@@ -9,14 +9,81 @@ paths:
|
|
|
9
9
|
|
|
10
10
|
# Python pytest 测试规范
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## 一、测试目录组织(强制)
|
|
13
|
+
|
|
14
|
+
### 核心约束
|
|
15
|
+
|
|
16
|
+
**测试目录与业务源码并列、独立存放。** 测试文件**禁止**混入源码目录(`src/` 或 `app/` 等)。
|
|
13
17
|
|
|
14
18
|
### 强制规则
|
|
19
|
+
|
|
20
|
+
- 测试目录与源码目录平级、独立,常用名 `tests/`(也可按团队约定,但**必须**独立)
|
|
21
|
+
- **禁止**在源码目录中放任何 `test_*.py` / `*_test.py` 文件
|
|
22
|
+
- 测试目录内部结构应**镜像**对应源码结构,便于定位被测对象
|
|
23
|
+
- 测试文件命名:`test_{被测模块名}.py`(pytest 默认发现规则)
|
|
24
|
+
- 测试函数命名:`test_{被测行为}` —— 描述行为而非实现
|
|
25
|
+
- 全局 fixture 放测试根目录的 `conftest.py`,子目录 fixture 放对应子目录的 `conftest.py`
|
|
26
|
+
- pytest 配置在 `pyproject.toml` 显式声明:
|
|
27
|
+
|
|
28
|
+
```toml
|
|
29
|
+
[tool.pytest.ini_options]
|
|
30
|
+
testpaths = ["tests"]
|
|
31
|
+
asyncio_mode = "auto"
|
|
32
|
+
python_files = ["test_*.py"]
|
|
33
|
+
python_functions = ["test_*"]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- 测试依赖(`pytest` / `pytest-asyncio` / `httpx` / `pytest-mock` 等)放 `[dev]` 或 `[test]` extras,**禁止**进生产依赖
|
|
37
|
+
- 跨包发布的代码不得 import 测试目录下的内容
|
|
38
|
+
|
|
39
|
+
> 具体目录布局由项目结构决定(单包、monorepo 子包、扁平 `app/` 等),AI 自行判断;唯一不变的是"测试目录独立、与源码并列"。
|
|
40
|
+
|
|
41
|
+
### 标准目录结构(仅供参考)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
project/
|
|
45
|
+
├── src/
|
|
46
|
+
│ └── app/
|
|
47
|
+
│ ├── routers/
|
|
48
|
+
│ │ └── user.py
|
|
49
|
+
│ ├── services/
|
|
50
|
+
│ │ └── user.py
|
|
51
|
+
│ ├── models/
|
|
52
|
+
│ │ └── user.py
|
|
53
|
+
│ └── main.py
|
|
54
|
+
├── tests/ # 测试根目录
|
|
55
|
+
│ ├── conftest.py # 全局 fixture(client / db_session 等)
|
|
56
|
+
│ ├── routers/
|
|
57
|
+
│ │ ├── __init__.py
|
|
58
|
+
│ │ └── test_user.py # 测 app/routers/user.py
|
|
59
|
+
│ ├── services/
|
|
60
|
+
│ │ ├── __init__.py
|
|
61
|
+
│ │ └── test_user.py # 测 app/services/user.py
|
|
62
|
+
│ └── models/
|
|
63
|
+
│ ├── __init__.py
|
|
64
|
+
│ └── test_user.py # 测 app/models/user.py
|
|
65
|
+
└── pyproject.toml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 二、技术栈
|
|
71
|
+
|
|
15
72
|
- 使用 `pytest` + `pytest-asyncio` + `httpx`
|
|
16
|
-
-
|
|
73
|
+
- API 测试使用 `httpx.AsyncClient` 配合 `ASGITransport`,**禁止**使用同步 `TestClient` 测异步路由
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 三、Fixture
|
|
78
|
+
|
|
79
|
+
### 强制规则
|
|
80
|
+
|
|
81
|
+
- 测试数据使用 `pytest.fixture`,**禁止**在测试函数中硬编码业务数据
|
|
82
|
+
- 数据库相关 fixture 必须保证测试间隔离(每个测试事务回滚或重建表)
|
|
83
|
+
- 跨测试共享的 fixture 放 `conftest.py`,单文件用的 fixture 留在文件内
|
|
17
84
|
|
|
18
85
|
```python
|
|
19
|
-
# conftest.py
|
|
86
|
+
# tests/conftest.py
|
|
20
87
|
import pytest
|
|
21
88
|
from httpx import ASGITransport, AsyncClient
|
|
22
89
|
from app.main import app
|
|
@@ -28,26 +95,61 @@ async def client():
|
|
|
28
95
|
base_url="http://test",
|
|
29
96
|
) as ac:
|
|
30
97
|
yield ac
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 四、测试编写规范
|
|
103
|
+
|
|
104
|
+
### 强制规则
|
|
105
|
+
|
|
106
|
+
- 测试结构遵循 **Arrange-Act-Assert**(准备 → 调用 → 断言)
|
|
107
|
+
- 一个测试只验证一个行为,**禁止**在一个 test 函数中堆多个不相关断言
|
|
108
|
+
- 断言要具体(断言字段值),**禁止**只断言"不报错"
|
|
109
|
+
- 必须覆盖:成功路径、失败路径(404 / 422 / 401 / 403)、边界值
|
|
110
|
+
- 敏感字段(密码、token)**必须**显式断言**不在**响应中
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# tests/routers/test_user.py
|
|
114
|
+
import pytest
|
|
115
|
+
from httpx import AsyncClient
|
|
31
116
|
|
|
32
|
-
# test_user.py
|
|
33
117
|
@pytest.mark.anyio
|
|
34
|
-
async def
|
|
35
|
-
|
|
118
|
+
async def test_create_user_returns_201_without_password(client: AsyncClient):
|
|
119
|
+
# Arrange
|
|
120
|
+
payload = {
|
|
36
121
|
"name": "Alice",
|
|
37
122
|
"email": "alice@example.com",
|
|
38
123
|
"password": "securepass123",
|
|
39
|
-
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Act
|
|
127
|
+
response = await client.post("/users/", json=payload)
|
|
128
|
+
|
|
129
|
+
# Assert
|
|
40
130
|
assert response.status_code == 201
|
|
41
131
|
data = response.json()
|
|
42
132
|
assert data["name"] == "Alice"
|
|
43
|
-
assert "password" not in data
|
|
133
|
+
assert "password" not in data
|
|
134
|
+
assert "hashed_password" not in data
|
|
44
135
|
|
|
45
136
|
@pytest.mark.anyio
|
|
46
137
|
async def test_get_nonexistent_user_returns_404(client: AsyncClient):
|
|
47
|
-
response = await client.get("/users/
|
|
138
|
+
response = await client.get("/users/00000000-0000-0000-0000-000000000000")
|
|
48
139
|
assert response.status_code == 404
|
|
49
140
|
```
|
|
50
141
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 五、违规检测清单
|
|
145
|
+
|
|
146
|
+
| 检查项 | 违规模式 | 严重程度 |
|
|
147
|
+
|--------|---------|---------|
|
|
148
|
+
| 测试与源码混放 | 测试文件放在 `src/` 或 `app/` 内(如 `app/services/test_user.py`) | 高 |
|
|
149
|
+
| 测试目录不规范 | 项目无 `tests/` 目录或 `pyproject.toml` 未配 `testpaths` | 高 |
|
|
150
|
+
| 镜像结构断裂 | 测试目录结构与源码目录结构不对应,难以定位 | 中 |
|
|
151
|
+
| 同步 TestClient | 异步路由用同步 `TestClient` 测试 | 高 |
|
|
152
|
+
| 测试无断言 | 只调用接口不断言响应字段 | 高 |
|
|
153
|
+
| 敏感字段未校验 | 用户接口测试未断言密码字段不在响应中 | 高 |
|
|
154
|
+
| 测试数据硬编码 | 复用的测试数据不抽 fixture,散落在多个 test 函数中 | 中 |
|
|
155
|
+
| 测试依赖泄漏 | `pytest` 等测试依赖进入生产依赖列表 | 高 |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Redis 安全与使用规范(必须用 dwyeapi 客户端、密码、绑定、危险命令禁用、key TTL 与前缀、敏感数据禁存)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Redis 安全与使用规范
|
|
6
|
+
|
|
7
|
+
适用于使用 Redis 作为缓存 / 会话存储 / Token 黑名单 / 速率限制存储的 Python 后端项目。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 一、客户端使用(强制)
|
|
12
|
+
|
|
13
|
+
- **必须**通过 dwyeapi 缓存模块获取共享异步 Redis 客户端(具体 API 查 `dwy-eapi` skill)
|
|
14
|
+
- **禁止**业务代码中 `aioredis.from_url(...)` 自建连接池
|
|
15
|
+
- **禁止**直接使用同步 `redis-py`(除非脚本类一次性任务)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 二、服务端配置(强制)
|
|
20
|
+
|
|
21
|
+
| 规则 | 说明 |
|
|
22
|
+
|------|------|
|
|
23
|
+
| 认证 | **必须**设置 `requirepass`,无密码 Redis 一律拒绝接入生产 |
|
|
24
|
+
| 绑定地址 | `bind 127.0.0.1` 或内网地址,**禁止** `bind 0.0.0.0` |
|
|
25
|
+
| 危险命令 | **禁用**或重命名 `FLUSHALL` / `FLUSHDB` / `CONFIG` / `KEYS` / `DEBUG` |
|
|
26
|
+
| 内存上限 | 设 `maxmemory` 与 `maxmemory-policy`(推荐 `allkeys-lru`),防止 OOM |
|
|
27
|
+
| 持久化 | 根据用途选择:缓存可关 AOF;会话 / 黑名单需 AOF everysec |
|
|
28
|
+
|
|
29
|
+
```conf
|
|
30
|
+
# redis.conf 关键项示例
|
|
31
|
+
requirepass <strong-password>
|
|
32
|
+
bind 127.0.0.1
|
|
33
|
+
rename-command FLUSHALL ""
|
|
34
|
+
rename-command FLUSHDB ""
|
|
35
|
+
rename-command CONFIG ""
|
|
36
|
+
rename-command KEYS ""
|
|
37
|
+
rename-command DEBUG ""
|
|
38
|
+
maxmemory 256mb
|
|
39
|
+
maxmemory-policy allkeys-lru
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 三、Key 设计规范(强制)
|
|
45
|
+
|
|
46
|
+
| 规则 | 说明 |
|
|
47
|
+
|------|------|
|
|
48
|
+
| 必须 TTL | 所有 key **必须**显式设置过期时间(`ex` / `pexpire`),**禁止**遗留无 TTL 的 key |
|
|
49
|
+
| 必须项目前缀 | 所有 key 必须有项目前缀,格式 `{app}:{domain}:{detail}`(如 `myapp:token:blacklist:abc123`) |
|
|
50
|
+
| snake_case | key 段用 snake_case,**禁止**驼峰或中文 |
|
|
51
|
+
| 不存敏感原文 | **禁止**存储密码、身份证、银行卡、token 原文(token 存哈希) |
|
|
52
|
+
|
|
53
|
+
### 正反例
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# 反例
|
|
57
|
+
await redis.set("abc123", "1") # 无前缀
|
|
58
|
+
await redis.set("myapp:data:xxx", value) # 无 TTL
|
|
59
|
+
await redis.set("myapp:user:password", "123456") # 存敏感原文
|
|
60
|
+
await redis.set("myapp:userToken", "ey...") # 驼峰命名
|
|
61
|
+
|
|
62
|
+
# 正例
|
|
63
|
+
await redis.set("myapp:token:blacklist:abc123", "1", ex=3600)
|
|
64
|
+
await redis.set("myapp:cache:user:uuid:f7e2", json_data, ex=300)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 四、Pub/Sub 与 Stream 使用约束
|
|
70
|
+
|
|
71
|
+
- 业务消息**禁止**用 Pub/Sub 当持久队列(Pub/Sub 无 ACK 与持久化)
|
|
72
|
+
- 持久任务用 dwyeapi tasks 模块(基于 ARQ)或 Redis Stream
|
|
73
|
+
- Stream 必须设消费者组 ACK 与死信处理
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 五、违规检测清单
|
|
78
|
+
|
|
79
|
+
| 检查项 | 违规模式 | 严重程度 |
|
|
80
|
+
|--------|---------|---------|
|
|
81
|
+
| 绑定 0.0.0.0 | 服务对公网暴露 | **致命 → STOP** |
|
|
82
|
+
| 无密码 | 生产 Redis 未设 `requirepass` | **致命 → STOP** |
|
|
83
|
+
| 存敏感原文 | 密码 / 身份证 / token 明文存 Redis | **致命 → STOP** |
|
|
84
|
+
| 自建连接池 | 业务代码 `aioredis.from_url(...)`,未走 dwyeapi 缓存模块 | 高 |
|
|
85
|
+
| 危险命令未禁 | `FLUSHALL` / `KEYS` / `CONFIG` 等可在生产执行 | 高 |
|
|
86
|
+
| Key 无 TTL | `redis.set()` 没有 `ex` 参数(业务上明确永久存储除外) | 中 |
|
|
87
|
+
| Key 无前缀 | Key 无项目前缀,污染共享 Redis | 中 |
|
|
88
|
+
| Pub/Sub 当队列 | 业务关键消息走 Pub/Sub | 高 |
|