feat: support durable task cancellation without foreign keys

This commit is contained in:
2026-09-17 17:03:23 +08:00
parent 6805506450
commit 3ce7d2c104
48 changed files with 1642 additions and 164 deletions

View File

@@ -98,6 +98,15 @@ func (s *ExecutionStore) Connect(ctx context.Context, token auth.Token, in worke
if registration != storedRegistration || epoch == ^uint64(0) {
return fault.Conflict
}
// 不依赖数据库外键:创建会话前验证队列存在且属于当前命名空间。
// 进程头在队列之前加锁,与执行命令保持一致;失败时回滚新建的进程头。
var queue core.ID
if err := tx.QueryRowContext(ctx, `SELECT id FROM pulse_queues WHERE namespace_id=? AND id=? FOR SHARE`, token.NamespaceID, in.QueueID).Scan(&queue); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return fault.NotFound
}
return err
}
now, err := dbNow(ctx, tx)
if err != nil {
return err
@@ -160,9 +169,13 @@ func (s *ExecutionStore) lockSession(ctx context.Context, tx *sql.Tx, token auth
if !p.AllowsQueue(state.queue) {
return state, fault.Forbidden
}
var node core.ID
var node, instance, sessionCredential core.ID
var sessionEpoch uint64
var raw []byte
err = tx.QueryRowContext(ctx, `SELECT node_id,capacity,capacity_sequence,capabilities,expires_at FROM pulse_worker_sessions WHERE namespace_id=? AND id=? FOR UPDATE`, token.NamespaceID, b.SessionID).Scan(&node, &state.capacity, &state.sequence, &raw, &state.expires)
err = tx.QueryRowContext(ctx, `SELECT node_id,worker_instance_id,credential_id,session_epoch,capacity,capacity_sequence,capabilities,expires_at FROM pulse_worker_sessions WHERE namespace_id=? AND id=? FOR UPDATE`, token.NamespaceID, b.SessionID).Scan(&node, &instance, &sessionCredential, &sessionEpoch, &state.capacity, &state.sequence, &raw, &state.expires)
if errors.Is(err, sql.ErrNoRows) {
return state, worker.StaleSession
}
if err != nil {
return state, err
}
@@ -170,7 +183,7 @@ func (s *ExecutionStore) lockSession(ctx context.Context, tx *sql.Tx, token auth
if err != nil {
return state, err
}
if node != s.node || !state.expires.After(now) {
if node != s.node || instance != b.InstanceID || sessionCredential != token.CredentialID || sessionEpoch != b.Epoch || !state.expires.After(now) {
return state, worker.StaleSession
}
if err := json.Unmarshal(raw, &state.capabilities); err != nil {