Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
package jobs
import "sync"
// DefaultSyncWorkers is the in-process bound for concurrent feed/Woo/Shopify syncs.
// Claim paths use FOR UPDATE SKIP LOCKED so each slot gets a distinct job.
const DefaultSyncWorkers = 1
// MaxSyncWorkers caps in-process sync parallelism (DB pool + upstream API RPM).
const MaxSyncWorkers = 2
// ClampSyncWorkers bounds n to [1, MaxSyncWorkers].
func ClampSyncWorkers(n int) int {
if n < 1 {
return 1
}
if n > MaxSyncWorkers {
return MaxSyncWorkers
}
return n
}
// SyncSlots limits concurrent sync Process* goroutines across feed/Woo/Shopify claims.
type SyncSlots struct {
Workers int
sem chan struct{}
wg sync.WaitGroup
}
// NewSyncSlots creates a bounded slot set for concurrent sync jobs.
func NewSyncSlots(workers int) *SyncSlots {
w := ClampSyncWorkers(workers)
return &SyncSlots{
Workers: w,
sem: make(chan struct{}, w),
}
}
// Wait blocks until all in-flight sync goroutines finish.
func (s *SyncSlots) Wait() {
s.wg.Wait()
}
// TryStart claims one free slot (non-blocking). claim must be SKIP LOCKEDsafe.
// If claim fails, the slot is released. On success, run executes in a new goroutine.
func (s *SyncSlots) TryStart(claim func() error, run func()) (started bool, claimErr error) {
select {
case s.sem <- struct{}{}:
default:
return false, nil
}
if err := claim(); err != nil {
<-s.sem
return false, err
}
s.wg.Add(1)
go func() {
defer s.wg.Done()
defer func() { <-s.sem }()
run()
}()
return true, nil
}