58 lines
1.4 KiB
Go
58 lines
1.4 KiB
Go
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
|
|
}
|