package settlement import ( "context" "fmt" "time" "gl/domain/ledger" ) type Repository interface { ClaimDue(context.Context, string, int, time.Time) ([]ledger.Settlement, error) Save(context.Context, ledger.Settlement, string) error } type Submitter interface { Submit(context.Context, ledger.Settlement) (string, error) } type Worker struct { Repository Repository Submitter Submitter WorkerID string MaxAttempts int Now func() time.Time } func (w Worker) RunOnce(ctx context.Context, limit int) error { if w.Repository == nil || w.Submitter == nil || w.WorkerID == "" || limit <= 0 { return fmt.Errorf("settlement worker is not configured") } now := time.Now().UTC() if w.Now != nil { now = w.Now().UTC() } records, err := w.Repository.ClaimDue(ctx, w.WorkerID, limit, now) if err != nil { return err } for _, record := range records { record.Attempts++ hash, submitErr := w.Submitter.Submit(ctx, record) if submitErr != nil { record = record.Retry(now, w.MaxAttempts, submitErr) } else { // Horizon returns success only after the transaction is accepted into // a ledger, so a successful response is already confirmation. record.Status = ledger.SettlementConfirmed record.TransactionHash = hash record.LastError = "" } if err := w.Repository.Save(ctx, record, w.WorkerID); err != nil { return err } } return nil }