mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-29 04:06:58 +00:00
fix captain record check ttl
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"atcr.io/pkg/appview/db"
|
||||
@@ -18,6 +19,10 @@ import (
|
||||
"atcr.io/pkg/auth/oauth"
|
||||
)
|
||||
|
||||
// captainCheckTTL is how long a successful captain XRPC fetch suppresses
|
||||
// further fetches for the same hold within this worker process.
|
||||
const captainCheckTTL = 1 * time.Hour
|
||||
|
||||
// BackfillWorker uses com.atproto.sync.listReposByCollection to backfill historical data
|
||||
type BackfillWorker struct {
|
||||
db *sql.DB
|
||||
@@ -26,6 +31,14 @@ type BackfillWorker struct {
|
||||
defaultHoldDID string // Default hold DID from AppView config (e.g., "did:web:hold01.atcr.io")
|
||||
testMode bool // If true, suppress warnings for external holds
|
||||
refresher *oauth.Refresher // OAuth refresher for PDS writes (optional, can be nil)
|
||||
|
||||
// captainChecked tracks the last time we successfully fetched each hold's
|
||||
// captain record from XRPC. This is the freshness gate for queryCaptainRecord
|
||||
// — we can't rely on the DB row's updated_at because UpsertCaptainRecord
|
||||
// intentionally skips writes (and thus the timestamp bump) when the captain
|
||||
// data hasn't changed, to avoid round-tripping no-op writes to remote libsql.
|
||||
captainCheckedMu sync.Mutex
|
||||
captainChecked map[string]time.Time
|
||||
}
|
||||
|
||||
// BackfillState tracks backfill progress
|
||||
@@ -55,6 +68,7 @@ func NewBackfillWorker(database *sql.DB, relayEndpoints []string, defaultHoldDID
|
||||
defaultHoldDID: defaultHoldDID,
|
||||
testMode: testMode,
|
||||
refresher: refresher,
|
||||
captainChecked: make(map[string]time.Time),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -478,15 +492,19 @@ func (b *BackfillWorker) queryCaptainRecordWrapper(ctx context.Context, holdDID
|
||||
return nil
|
||||
}
|
||||
|
||||
// queryCaptainRecord queries a hold's captain record and caches it in the database
|
||||
// queryCaptainRecord queries a hold's captain record and caches it in the database.
|
||||
//
|
||||
// Freshness is tracked in an in-memory map keyed by hold DID rather than the
|
||||
// row's updated_at column. UpsertCaptainRecord deliberately skips no-op writes
|
||||
// to avoid round-tripping unchanged data to remote libsql, which means
|
||||
// updated_at is "last time data changed" not "last time we checked" — using it
|
||||
// as a freshness gate would re-fetch on every call once the row aged past TTL.
|
||||
func (b *BackfillWorker) queryCaptainRecord(ctx context.Context, holdDID string) error {
|
||||
// Check if we already have it cached (skip if recently updated)
|
||||
existing, err := db.GetCaptainRecord(b.db, holdDID)
|
||||
if err == nil && existing != nil {
|
||||
// If cached within last hour, skip refresh
|
||||
if time.Since(existing.UpdatedAt) < 1*time.Hour {
|
||||
return nil
|
||||
}
|
||||
b.captainCheckedMu.Lock()
|
||||
last, ok := b.captainChecked[holdDID]
|
||||
b.captainCheckedMu.Unlock()
|
||||
if ok && time.Since(last) < captainCheckTTL {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resolve hold DID to URL
|
||||
@@ -531,6 +549,10 @@ func (b *BackfillWorker) queryCaptainRecord(ctx context.Context, holdDID string)
|
||||
return fmt.Errorf("failed to cache captain record: %w", err)
|
||||
}
|
||||
|
||||
b.captainCheckedMu.Lock()
|
||||
b.captainChecked[holdDID] = time.Now()
|
||||
b.captainCheckedMu.Unlock()
|
||||
|
||||
slog.Info("Backfill cached captain record for hold", "hold_did", holdDID, "owner_did", captainRecord.OwnerDID)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -223,6 +223,12 @@ func NewS3Service(params map[string]any) (*S3Service, error) {
|
||||
// with trailers, which causes XAmzContentSHA256Mismatch errors on
|
||||
// S3-compatible services that don't support this.
|
||||
o.RequestChecksumCalculation = aws.RequestChecksumCalculationWhenRequired
|
||||
// Mirror on the response side. Default is WhenSupported, which logs a
|
||||
// WARN on every GetObject whose response lacks x-amz-checksum-* —
|
||||
// i.e. every read against Storj/R2/MinIO/Backblaze. The bytes are fine,
|
||||
// the warning is just SDK chatter; switch to WhenRequired so the SDK
|
||||
// only validates when the server actually returned a checksum.
|
||||
o.ResponseChecksumValidation = aws.ResponseChecksumValidationWhenRequired
|
||||
})
|
||||
|
||||
var s3PathPrefix string
|
||||
|
||||
Reference in New Issue
Block a user