8d838d9cb4
build / build (push) Successful in 1m45s
执行时真实时钟与持久授权回读(撤销/过期即停并保留预备份)、写集合写前落盘、 租约与 attempt 身份、恢复队列与原发送身份分离、成功收尾必须释放维护后再登记终态。
37 lines
1.1 KiB
Go
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)
|
|
}
|