Files
knowledge-governance/internal/platform/postgres/library_execution.go
姚章浩 8d838d9cb4
build / build (push) Successful in 1m45s
feat(library): 整库发布身份、写集合与收尾边界
执行时真实时钟与持久授权回读(撤销/过期即停并保留预备份)、写集合写前落盘、
租约与 attempt 身份、恢复队列与原发送身份分离、成功收尾必须释放维护后再登记终态。
2026-11-01 11:35:10 +08:00

37 lines
1.1 KiB
Go

package postgres
import (
"context"
"errors"
"time"
)
var ErrLibraryExecutionBusy = errors.New("target already has an active executor")
func (s *Store) WithLibraryExecution(ctx context.Context, instance string, run func(context.Context, func(context.Context) error) error) error {
if instance == "" {
return errors.New("execution instance identity required")
}
// A lease expiry is not proof that the old writer has stopped. Keep a
// shared PG advisory lock until the synchronous callback (including cleanup)
// exits. No deferred unlock may run merely because ctx was cancelled.
tx, err := s.db.Begin(ctx)
if err != nil {
return err
}
defer func() {
cleanup, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
defer cancel()
_ = tx.Rollback(cleanup)
}()
var held bool
if err = tx.QueryRow(ctx, `SELECT pg_try_advisory_xact_lock(hashtextextended($1,0))`, "library-execution:"+instance).Scan(&held); err != nil {
return err
}
if !held {
return ErrLibraryExecutionBusy
}
ping := func(probe context.Context) error { var one int; return tx.QueryRow(probe, `SELECT 1`).Scan(&one) }
return run(ctx, ping)
}