proxy-pool/internal/domain/ownership/ownership.go
youfak 88d5ac24d4
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: bind drain tickets to full snapshots
2026-08-02 11:02:19 +08:00

65 lines
2.2 KiB
Go

package ownership
import (
"context"
"crypto/sha256"
"errors"
"time"
)
var (
ErrInvalidOwnership = errors.New("invalid proxy ownership request")
ErrOwnershipUnavailable = errors.New("proxy is unavailable for ownership")
ErrAlreadyOwned = errors.New("proxy is already owned")
ErrStaleAssignment = errors.New("proxy ownership assignment is stale")
ErrNotDraining = errors.New("proxy ownership is not draining")
ErrDrainNotReady = errors.New("proxy still has active or reserved runtime")
ErrInvalidDrainTicket = errors.New("invalid drain ticket request")
)
type Assignment struct {
ProxyID string
WorkerID string
Epoch uint64
Version uint64
ExpiresAt time.Time
Draining bool
}
// DrainTicket records a pending removal after an ownership assignment enters
// draining. RequiredSnapshotEpoch fences the first complete Worker snapshot
// that may prove the proxy was excluded.
type DrainTicket struct {
ProxyID string
WorkerID string
AssignmentEpoch uint64
RequiredSnapshotEpoch uint64
Barrier SnapshotBarrier
}
type SnapshotBarrier struct {
SessionID string
Version uint64
OwnershipEpoch uint64
Checksum [sha256.Size]byte
}
// DrainTicketStore exposes bounded, Worker-local pending drain tickets. It
// deliberately does not finalize ownership: a later runtime transaction must
// prove both an acknowledged exclusion snapshot and zero live counters.
type DrainTicketStore interface {
PendingDrains(context.Context, string, int) ([]DrainTicket, error)
BindDrainBarrier(context.Context, DrainTicket) error
}
// Repository is the shared authority for ownership changes. Implementations
// that also support extraction must serialize both operations transactionally.
type Repository interface {
Assign(context.Context, time.Time, string, string, time.Duration) (Assignment, error)
Renew(context.Context, time.Time, string, string, uint64, time.Duration) (Assignment, error)
BeginDrain(context.Context, string, string, uint64) (Assignment, error)
AcknowledgeDrain(context.Context, string, string, uint64, int64, int64) error
Get(context.Context, string) (Assignment, bool, error)
Expire(context.Context, time.Time, int) ([]Assignment, error)
}