Files
data-engine/docs/USAGE.md
2026-05-29 18:39:32 +08:00

364 lines
12 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.
# Data Engine 通用数据同步引擎 - 使用文档
## 一、概述
本系统是一个**配置驱动的通用数据同步引擎**,核心思想是:**平台管理 + 接口管理**。
您只需要通过 API 维护好平台和接口的配置信息(认证方式、请求参数、响应解析、目标表结构),系统就会自动:
1. **创建目标表**(根据 `table_definition` 自动建表)
2. **拉取数据**(分页请求、多步骤请求、并发处理)
3. **写入数据库**(批量 upsert
4. **增量同步**(通过 `filtering` 按最后修改时间过滤)
5. **自动调度**(按配置的时间间隔循环执行)
6. **补偿重试**(失败的同步任务自动重试,退避递增)
**不需要为每个平台写一行业务代码。**
---
## 二、数据库初始化
### 2.1 核心表
首次使用需执行 `sql/init_core_tables.sql`,创建以下 4 张表:
| 表名 | 说明 |
|------|------|
| `api_datasource_platform` | 数据源平台配置(认证信息、限流等) |
| `api_interface` | 接口配置URL、请求参数、表结构等 |
| `sync_task_log` | 同步任务日志(记录状态,用于补偿) |
| `sync_tracker` | 同步跟踪(记录每个接口的最后同步时间) |
### 2.2 初始化数据
执行 `sql/seed_data.sql` 创建腾讯广告平台+接口配置。如需清空重来:
```sql
ALTER SEQUENCE api_datasource_platform_id_seq RESTART WITH 1;
ALTER SEQUENCE api_interface_id_seq RESTART WITH 1;
DELETE FROM api_interface;
DELETE FROM api_datasource_platform;
\i sql/seed_data.sql
```
---
## 三、配置说明
### 3.1 平台管理 (`api_datasource_platform`)
| 字段 | 说明 | 示例 |
|------|------|------|
| `platform_code` | 平台编码(唯一) | `tencent` |
| `platform_name` | 平台名称 | `腾讯广告` |
| `api_base_url` | API 基础地址 | `https://api.e.qq.com/v3.0` |
| `auth_type` | 认证类型 | `OAUTH2` / `TOKEN` / `API_KEY` / `BASIC` |
| `token` | access_token | `xxxxx` |
| `client_id` / `client_secret` | OAuth2 凭证 | `xxxxx` |
| `auth_config` | 自定义认证配置(JSONB) | 详见 3.1.1 |
#### 3.1.1 `auth_config` 字段详解
```json
{
"token_in_query": true, // token 放在 URL 查询参数
"query_key": "access_token", // 参数名,默认 "access_token"
"header_name": "Authorization", // token 放请求头时的头名
"header_format": "Bearer {token}",
"extra_query_params": { // 额外查询参数
"timestamp": "{timestamp}", // {timestamp} 自动替换为当前时间戳
"nonce": "{nonce}" // {nonce} 自动替换为随机字符串
}
}
```
### 3.2 接口管理 (`api_interface`)
| 字段 | 说明 | 示例 |
|------|------|------|
| `platform_id` | 所属平台 ID | `1` |
| `name` / `code` | 接口名称 / 唯一编码 | `图片素材` / `image` |
| `url` | 接口地址(相对路径) | `/images/get` |
| `method` | 请求方法 | `GET` / `POST` |
| `request_config` | 请求配置(JSONB) | 详见 3.2.1 |
| `response_config` | 响应配置(JSONB) | 详见 3.2.2 |
| `table_definition` | 表结构定义(JSONB) | 详见 3.3 |
#### 3.2.1 `request_config` 字段详解
```json
{
"parameters_location": "query", // 参数位置: "query"(URL) / "body"(默认)
"page": 1,
"page_size": 100,
"page_param": "page", // 分页参数名(自定义)
"page_size_param": "page_size",
"time_field": "last_modified_time", // 增量时间字段
"fields": ["field1", "field2"], // 请求字段(如音频的 fields
"prefetch": { ... } // 预取配置(见下文)
}
```
**`parameters_location` 说明**
- 未设置或 `"body"` → 参数放在 JSON body 中POST 请求)
- `"query"` → 参数放在 URL 查询字符串中GET 请求用)
-`method=GET` 时,即使不设置也默认走 query
**预取prefetch**:某些接口需要"先拿列表→遍历每个元素查数据"(如先拉账户列表,再遍历拉图片)。
```json
"prefetch": {
"url": "/advertiser/get", // 预取接口地址
"method": "GET",
"response_path": "data.list", // 从响应中取值路径
"target_param": "account_id", // 注入主请求的参数名
"value_field": "account_id" // 从预取结果取哪个字段
}
```
**并发处理**:有 prefetch 的接口会并发处理每个实体,并发数由 `config.yml``sync.concurrency` 控制。
**增量同步**:配置了 `time_field` 的接口,增量同步时会自动生成 `filtering` 参数:
```json
{"field": "last_modified_time", "operator": "GREATER_EQUALS", "values": ["<timestamp>"]}
```
#### 3.2.2 `response_config` 字段详解
系统默认解析的响应格式:
```json
{ "code": 0, "message": "success", "data": { "list": [...], "page_info": { "total_page": N } } }
```
可通过 `response_config` 自定义数据路径:
```json
{ "list_path": "data.list" }
```
### 3.3 `table_definition` 字段详解
```json
{
"table_name": "tencent_image",
"columns": [
{ "name": "image_id", "type": "VARCHAR(100)", "comment": "图片ID" },
{ "name": "account_id", "type": "BIGINT", "comment": "账户ID" }
],
"conflict_keys": ["image_id", "account_id"]
}
```
**自动添加的列**(无需声明):
| 列名 | 类型 | 说明 |
|------|------|------|
| `id` | BIGSERIAL PRIMARY KEY | 自增主键 |
| `tenant_id` | BIGINT | 租户 ID |
| `creator` | VARCHAR(64) | 创建人 |
| `created_at` | TIMESTAMPTZ | 创建时间 |
| `updater` | VARCHAR(64) | 更新人 |
| `updated_at` | TIMESTAMPTZ | 更新时间 |
| `deleted_at` | TIMESTAMPTZ | 软删除 |
| `raw_data` | JSONB | 原始响应数据 |
---
## 四、API 接口
基础地址:`http://localhost:3002`
### 4.1 平台管理
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/datasourcePlatform/createDatasourcePlatform` | 创建平台 |
| GET | `/api/datasourcePlatform/listDatasourcePlatforms` | 列表 |
| GET | `/api/datasourcePlatform/getDatasourcePlatform` | 详情 |
| GET | `/api/datasourcePlatform/getPlatformByCode` | 按编码查 |
| PUT | `/api/datasourcePlatform/updateDatasourcePlatform` | 更新 |
| PUT | `/api/datasourcePlatform/updateDatasourcePlatformStatus` | 更新状态 |
| DELETE | `/api/datasourcePlatform/deleteDatasourcePlatform` | 删除 |
| GET | `/api/datasourcePlatform/getPlatformStatistics` | 统计 |
### 4.2 接口管理
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/apiInterface/createApiInterface` | 创建接口 |
| GET | `/api/apiInterface/listApiInterfaces` | 列表 |
| GET | `/api/apiInterface/getApiInterface` | 详情 |
| PUT | `/api/apiInterface/updateApiInterface` | 更新 |
| PUT | `/api/apiInterface/updateApiInterfaceStatus` | 更新状态 |
| DELETE | `/api/apiInterface/deleteApiInterface` | 删除 |
### 4.3 同步控制
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/sync/ctrl/trigger` | 触发同步 |
| GET | `/api/sync/ctrl/config` | 查询配置 |
**触发同步示例:**
```bash
curl -X POST http://localhost:3002/api/sync/ctrl/trigger \
-H 'Content-Type: application/json' \
-d '{"platformCode":"tencent","interfaceCode":"image","fullSync":true}'
```
响应:
```json
{
"success": true,
"tableName": "tencent_image",
"totalRows": 1500,
"insertedRows": 1450,
"duration": "12.3s"
}
```
---
## 五、配置文件 (`config.yml`)
```yaml
sync:
page_size: 100 # 每次分页请求条数
concurrency: 5 # 并发处理数prefetch 遍历实体时)
retry_count: 3 # 最大重试次数
sync_interval_minutes: 60 # 自动同步间隔(分钟)
compensation_interval_seconds: 300 # 补偿扫描间隔(秒)
auto_sync_enabled: true # 是否启用自动同步
tencent:
oauth:
client_id: "1112038234"
client_secret: "GxyjXFbZAs5dnsNQ"
access_token: "4bacfc7c9b0a31f70ec0eb4771f8b542"
refresh_token: "d15b37363a42449026d337708516e95e"
```
---
## 六、自动同步机制
### 6.1 启动流程
1. 服务启动 → `InitAndStartAutoSync` 在 goroutine 中启动调度器
2. 自动扫描所有 ACTIVE 平台下有 `table_definition` 的接口
3.`sync_tracker` 记录 → 全量拉取;有记录 → 增量拉取
### 6.2 增量同步原理
- `sync_tracker` 表记录每个接口的最后同步时间
- 配置了 `time_field` 的接口,增量时生成 `filtering=[{"field":"last_modified_time","operator":"GREATER_EQUALS","values":["<时间戳>"]}]`
- 不支持时间过滤的接口(如 audio/advertiser每次全量`ON CONFLICT` 去重
### 6.3 异常中断恢复
- 同步开始前写 `sync_tracker.sync_status='running'`
- 同步完成后写 `'success'`
- 重启检测到 `'running'` → 日志告警 → 重新全量
---
## 七、补偿机制
### 7.1 工作原理
1. 同步失败 → 自动写入 `sync_task_log`status=failed
2. 补偿调度器(随主服务自动启动)每 N 秒扫描 failed 记录
3. 对未达最大重试次数的任务,调用 `SyncByConfig` 重试
4. 重试间隔按退避策略递增5min → 15min → 30min → 60min → 120min
5. 达最大次数 → 标记 `manual_review`,等待人工介入
### 7.2 配置
```yaml
sync:
compensation_interval_seconds: 300 # 扫描间隔
retry_count: 3 # 最大重试次数
```
补偿调度器随主服务自动启动,无需手动运行。
---
## 八、当前已配置接口(腾讯广告)
| 接口编码 | 名称 | 方法+路径 | 类型 | 增量 |
|------|------|------|------|------|
| `account_relation` | 账户列表 | `GET /advertiser/get` | 单接口分页 | 不支持 |
| `image` | 图片素材 | `GET /images/get` | prefetch 遍历账户 | ✅ `last_modified_time` |
| `video` | 视频素材 | `GET /videos/get` | prefetch 遍历账户 | ✅ `last_modified_time` |
| `audio` | 音频素材 | `POST /muse_audios/get` | 单接口 POST | 不支持 |
三个素材表自动包含 `verify_status DEFAULT 'PENDING'``verified_at``verified_by` 校验字段。
### 图片/视频同步流程
```
SyncByConfig("tencent", "image")
├── ① 预取: 分页拉取 /advertiser/get → 774 个 account_id
│ 数据同时存入 tencent_account_relation 表
├── ② 并发遍历账户config.yml concurrency=5
│ 每个 account_id → GET /images/get?account_id=xxx&page=1&page_size=100
│ 自动补充 filtering增量时
│ 结果 upsert 到 tencent_image
└── ③ 更新 sync_tracker 记录同步时间
```
### 音频同步流程
```
单次 POST /muse_audios/get → 分页拉全量 → upsert 到 tencent_audio
```
---
## 九、快速开始
```bash
# 1. 建表
psql -h localhost -U postgres -d data-engine -f sql/init_core_tables.sql
# 2. 初始化数据
psql -h localhost -U postgres -d data-engine -f sql/seed_data.sql
# 3. 启动
go run main.go
```
启动后自动同步和补偿调度器自动运行。也可手动触发:
```bash
# 触发图片全量同步
curl -X POST http://localhost:3002/api/sync/ctrl/trigger \
-H 'Content-Type: application/json' \
-d '{"platformCode":"tencent","interfaceCode":"image","fullSync":true}'
```
---
## 十、常见问题
**Q: 响应格式不符合 `{code: 0, data: {list: [...]}}` 怎么办?**
修改 `dynamic_sync.go``parseResp` 函数。
**Q: 如何添加新平台?**
调用平台管理 API 创建平台 → 调用接口管理 API 创建接口(带 `table_definition`)→ 系统自动建表并同步。
**Q: prefetch 的响应格式要求?**
必须是 JSON`response_path` 指向一个数组。如 `response_path: "data.list"``data.list` 取值。
**Q: 如何排查同步失败?**
1. `GET /api/sync/ctrl/config?platformCode=xxx` 查看配置
2. 查询 `sync_task_log` 表看失败记录
3. 补偿调度器会自动重试,日志会打印重试过程