Files
backend_v2/internal/model/crawl_task.go
toom1996 151e09ab30 feat: 抓取任务队列 + 媒体机直传 + 向量回填
crawl(品牌抓取任务队列)
- /admin/internal/crawl/tasks 领取 / :id/result 回报,spider 可常驻拉任务
- 后台品牌列表支持「加入抓取队列」,队列页可看状态与重试
- 租约超时的 running 自动回收为 queued,避免 worker 崩溃后任务卡死

media(媒体机直传)
- ingest 载荷新增 main_key/detail_keys/main_size/detail_sizes:
  有 key 就直接落库,跳过下载与上传;与 URL 形态可逐图混用
- 细节图按 Details/DetailKeys 两者较长者遍历(只给 key 时不再丢图)
- 媒体机上传的 key 不进失败回滚清单(内容寻址、可能与他人共享)
- /admin/internal/upload-url 签发 S4 PUT 预签名(spider 不持有 AK/SK)

embeddings(向量回填)
- GET /admin/internal/embeddings/pending 派发缺向量的图(含可直接下载的 url)
- POST /admin/internal/embeddings 回写向量并重算近邻;失败项计入
  image_embedding_failures,连续失败到上限后退出队列(坏图不占位)
- 近邻重算改为异步串行:同步会让 100 张的批次 POST 超时(实测 >60s)
- 新增 key 分支单测:混用 key/url、细节图只给 key、字节数、回滚清单、向量占位
2026-10-25 00:37:13 +08:00

58 lines
3.1 KiB
Go
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.

package model
// CrawlTask 后台派发给爬虫服务的「品牌抓取任务」。
//
// 与 ingest_jobs 的分工:
// - ingest_jobs:一场走秀的入库任务,由后端 worker 消费(下载图 / 写库 / 编码);
// - crawl_tasks:一个品牌的抓取任务,由 spider 服务领取执行(可能在另一台机器)。
//
// 两层解耦的好处:后台只需表达「我要爬哪些品牌」,不必关心 spider 在哪、跑几个。
// spider 拉不到任务就空转,任务积压也不会影响已有数据的读写。
const (
CrawlQueued = "queued" // 待领取
CrawlRunning = "running" // 已被某个 worker 领取
CrawlDone = "done" // 执行完成(不代表每场都入库成功,见 last_error)
CrawlFailed = "failed" // 执行失败(spider 进程报错 / 品牌在 Vogue 无页面等)
CrawlCanceled = "canceled" // 后台手动取消
)
// CrawlStuckTimeoutSec 是 running 任务的租约时长:超过该时长仍未回报,
// 视为 worker 已崩溃(断电 / 被杀),任务可被重新领取,避免永久卡在 running。
const CrawlStuckTimeoutSec = 900
// CrawlMaxAttempts 自动重试上限;达到后置 failed,需后台手动「重试」。
const CrawlMaxAttempts = 3
// CrawlTask 品牌抓取任务。
// 时间字段与项目其它表一致,统一用 Unix 秒(uint32)。
type CrawlTask struct {
ID uint32 `gorm:"primaryKey;column:id" json:"id"`
BrandID uint32 `gorm:"column:brand_id;not null" json:"brand_id"`
// Status 见上方常量;默认 queued。
Status string `gorm:"column:status;size:16;not null;default:'queued'" json:"status"`
// Priority 越大越先被领取;用于「手动加的」优先于「批量加的」。
Priority int16 `gorm:"column:priority;not null;default:0" json:"priority"`
// MaxShows 单品牌最多抓几场(0=不限)。批量重爬历史品牌时用它控制入库量。
MaxShows int16 `gorm:"column:max_shows;not null;default:0" json:"max_shows"`
// Worker 领取者标识(主机名 + 进程号),便于排查「谁跑的」。
Worker string `gorm:"column:worker;size:64;not null;default:''" json:"worker"`
// LockedAt 领取时间,配合 CrawlStuckTimeoutSec 做租约回收。
LockedAt uint32 `gorm:"column:locked_at;not null;default:0" json:"locked_at"`
// Attempts 已被领取次数;用于自动重试与放弃判定。
Attempts int16 `gorm:"column:attempts;not null;default:0" json:"attempts"`
// ShowsSubmitted 本任务向 ingest 提交了多少场走秀(spider 回报)。
ShowsSubmitted int32 `gorm:"column:shows_submitted;not null;default:0" json:"shows_submitted"`
LastError string `gorm:"column:last_error;type:text" json:"last_error"`
CreatedAt uint32 `gorm:"column:created_at;not null;default:0" json:"created_at"`
UpdatedAt uint32 `gorm:"column:updated_at;not null;default:0" json:"updated_at"`
}
// TableName 指定表名。
func (CrawlTask) TableName() string { return "crawl_tasks" }
// CrawlTaskRow 是列表/领取接口用的投影行,附带品牌名(列表展示与拼 Vogue URL 都用得上)。
type CrawlTaskRow struct {
CrawlTask
BrandName string `gorm:"column:brand_name"`
}