PDD 商品页要能「创建采集任务」而不指定客户端——采集只是浏览商品页, 没有副作用,哪台设备采都一样,没必要每次都挑一台。
但现在 claim 的查询是:
claim
WHERE assigned_client = ? AND status = 'assigned'
无主任务(assigned_client IS NULL + status='pending')永远不会被任何客户端领到。 不改这里,建出来的采集任务就是死的。
assigned_client IS NULL
status='pending'
这条改动推翻了一条已定案的规则: docs/client/04-admin-api-contract.md §5.1 现在写着「Admin 只把任务分配给指定的 Client」。
docs/client/04-admin-api-contract.md
做:
ClaimNextTask
assigned_client
不做:
status
pending
WHERE task_type IN (...) AND ( (assigned_client = ? AND status = 'assigned') -- 指定给我的 OR (assigned_client IS NULL AND status = 'pending') ) -- 无主的 ORDER BY (assigned_client IS NULL), priority DESC, created_at
[必须] 指定给我的优先于无主的(ORDER BY (assigned_client IS NULL) 让 0 排在 1 前面)。 理由:显式分配是人为决定,应当先兑现;无主任务谁抢都一样,可以等。
[必须]
ORDER BY (assigned_client IS NULL)
两种情况可以合成一条语句——对"指定给我的"那种,写入 assigned_client 是写同一个值,无副作用:
UPDATE tasks SET status = 'claimed', assigned_client = ?, claimed_at = ?, updated_at = ? WHERE task_id = ? AND ( (status = 'assigned' AND assigned_client = ?) OR (status = 'pending' AND assigned_client IS NULL) )
[必须] 检查影响行数,为 0 说明被别人抢先了,换下一条候选。这是防并发重复领取的唯一手段, SQLite 没有 SELECT ... FOR UPDATE。
SELECT ... FOR UPDATE
[必须] 领取成功后仍要写 task_claims——提交结果时的权限判断依赖它 (只有从没领过的才返回 403,见 docs/admin/04-client-api.md §4.1)。
task_claims
docs/admin/04-client-api.md
admin/repository/task.go
admin/service/client_test.go
claimed
claimed_at
supported_types
go vet
gofmt -l .
go test ./...
cd D:\chengma\cmautobuy\admin go vet ./... gofmt -l . go test ./... -count=1
不需要真机,不需要 Client。
tasks
回退:改动集中在 admin/repository/task.go,git revert 即可,无表结构变更。
git revert
dd387e3
fab20cf
docs/task/17-admin-claim-支持领取无主任务.md
go vet / gofmt -l . 无输出;go test ./... -count=1 62 个测试全 PASS(新增 7 个)。
go test ./... -count=1
并发用例重复 20 次稳定:8 个客户端抢同一条无主任务,正好 1 个拿到, 且库里 assigned_client 记的就是那个赢家。
优先级那条测试特意构造成「无主任务的 created_at 更早」—— 没有优先级规则的话按 created_at 排序会先拿到无主的,测试就会红。
created_at
10 条验收标准全部通过。
docs/client/04-admin-api-contract.md §5.1 从「Admin 只把任务分配给指定的 Client」 改为两种并存:采集任务不指定,采购任务可指定可留空。全库已无「只分配给指定 Client」的残留说法。
HttpAdminGateway
register_client
tasks 表缺「该任务需要真实下单」的标记字段,本次把无主任务开放给所有客户端后, 这条风险被放大:声明 dry_run 的客户端可能抢到本该真实下单的任务。 当前真实下单开关默认关闭、全部演练模式,不出问题;开启前必须补该字段。 经确认暂不单独建工单。
dry_run
用户确认验收通过。归档状态已更新(3fdab7b)。
3fdab7b
遗留:tasks 表缺「该任务需要真实下单」的标记字段。当前真实下单开关默认关闭、全部演练模式,不出问题;开启前必须补该字段。
No dependencies set.
The note is not visible to the blocked user.
基本信息
要解决什么
PDD 商品页要能「创建采集任务」而不指定客户端——采集只是浏览商品页,
没有副作用,哪台设备采都一样,没必要每次都挑一台。
但现在
claim的查询是:无主任务(
assigned_client IS NULL+status='pending')永远不会被任何客户端领到。不改这里,建出来的采集任务就是死的。
这条改动推翻了一条已定案的规则:
docs/client/04-admin-api-contract.md§5.1 现在写着「Admin 只把任务分配给指定的 Client」。做什么 / 不做什么
做:
ClaimNextTask支持两种任务:指定给本机的 + 无主的assigned_client("谁领到就标记谁")不做:
assigned_client本来可空,status已有pending)怎么做
查询
[必须]指定给我的优先于无主的(ORDER BY (assigned_client IS NULL)让 0 排在 1 前面)。理由:显式分配是人为决定,应当先兑现;无主任务谁抢都一样,可以等。
原子抢占
两种情况可以合成一条语句——对"指定给我的"那种,写入
assigned_client是写同一个值,无副作用:[必须]检查影响行数,为 0 说明被别人抢先了,换下一条候选。这是防并发重复领取的唯一手段,SQLite 没有
SELECT ... FOR UPDATE。[必须]领取成功后仍要写task_claims——提交结果时的权限判断依赖它(只有从没领过的才返回 403,见
docs/admin/04-client-api.md§4.1)。分配策略
预计修改文件
admin/repository/task.goClaimNextTask查询与原子更新admin/service/client_test.godocs/client/04-admin-api-contract.mddocs/admin/04-client-api.md验收标准
assigned_client被写成领取者的编号status变为claimed,claimed_at有值supported_types过滤仍然生效(只声明 collect 的不会拿到 purchase)task_claims有对应记录go vet/gofmt -l ./go test ./...全过怎么验证
不需要真机,不需要 Client。
风险和回退
tasks表目前没有字段标记任务是否需要真实下单。真实下单开关默认关闭时不出问题,开启前必须补该字段——记入后续工单回退:改动集中在
admin/repository/task.go,git revert即可,无表结构变更。实施完成,待验收
dd387e3feat: claim 支持领取无主任务 (#17)fab20cfdocs: 归档任务 #16 Admin:claim 支持领取无主任务 (#17)docs/task/17-admin-claim-支持领取无主任务.md验证结果(Go 1.23.0)
go vet/gofmt -l .无输出;go test ./... -count=162 个测试全 PASS(新增 7 个)。并发用例重复 20 次稳定:8 个客户端抢同一条无主任务,正好 1 个拿到,
且库里
assigned_client记的就是那个赢家。优先级那条测试特意构造成「无主任务的
created_at更早」——没有优先级规则的话按
created_at排序会先拿到无主的,测试就会红。10 条验收标准全部通过。
契约变更
docs/client/04-admin-api-contract.md§5.1 从「Admin 只把任务分配给指定的 Client」改为两种并存:采集任务不指定,采购任务可指定可留空。全库已无「只分配给指定 Client」的残留说法。
未验证到的部分
claim接口本身未改,改动全在 repository 查询里)HttpAdminGateway目前只实现了register_client遗留
tasks表缺「该任务需要真实下单」的标记字段,本次把无主任务开放给所有客户端后,这条风险被放大:声明
dry_run的客户端可能抢到本该真实下单的任务。当前真实下单开关默认关闭、全部演练模式,不出问题;开启前必须补该字段。
经确认暂不单独建工单。
验收通过,关闭
用户确认验收通过。归档状态已更新(
3fdab7b)。dd387e3docs/task/17-admin-claim-支持领取无主任务.md遗留:
tasks表缺「该任务需要真实下单」的标记字段。当前真实下单开关默认关闭、全部演练模式,不出问题;开启前必须补该字段。