feat: add idempotent batch task submission and recovery examples

This commit is contained in:
2026-09-17 21:21:18 +08:00
parent a8a8dcfe1e
commit 571107f96d
27 changed files with 1375 additions and 24 deletions

View File

@@ -28,6 +28,11 @@ func NewTaskStore(db *sql.DB) *TaskStore { return &TaskStore{db: db} }
var _ service.Store = (*TaskStore)(nil)
// AuthorizeSubmit 用于批量请求的只读预认证;每项事务仍独立校验凭据、动作与队列范围。
func (s *TaskStore) AuthorizeSubmit(ctx context.Context, token auth.Token) error {
return s.transaction(ctx, token, "tasks:submit", func(*sql.Tx, auth.Permissions) error { return nil })
}
func (s *TaskStore) transaction(ctx context.Context, token auth.Token, action string, fn func(*sql.Tx, auth.Permissions) error) error {
return WithTx(ctx, s.db, func(tx *sql.Tx) error {
p, err := authenticate(ctx, tx, token)
@@ -159,6 +164,12 @@ func (s *TaskStore) Submit(ctx context.Context, token auth.Token, key string, in
if !p.AllowsQueue(in.QueueID) {
return fault.Forbidden
}
// 先按既有应用额度锁串行进入受理,再占用幂等唯一键。
// 满额回滚时,同键并发INSERT的重复检查锁不能与应用额度锁互相等待。
// 此处只取得锁,不检查/扣减额度;已有回执在满额时仍可返回。
if _, err := lockApplicationResources(ctx, tx, token.NamespaceID, false); err != nil {
return err
}
taskID, err := core.NewID()
if err != nil {
return err
@@ -174,7 +185,7 @@ func (s *TaskStore) Submit(ctx context.Context, token auth.Token, key string, in
out.Deduplicated = true
return nil
}
if _, _, err := lockQueue(ctx, tx, token.NamespaceID, in.QueueID); err != nil {
if _, _, err := lockQueueAfterApplication(ctx, tx, token.NamespaceID, in.QueueID); err != nil {
return err
}
now, err := dbNow(ctx, tx)