80 lines
2.7 KiB
Go
80 lines
2.7 KiB
Go
// Command replay-outbox publishes one explicitly bounded wallet owner-outbox
|
|
// batch. It is intentionally separate from the long-running server worker:
|
|
// batch-size there controls one poll, while --limit here caps the whole process.
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"hyapp/pkg/outboxreplay"
|
|
"hyapp/services/wallet-service/internal/app"
|
|
"hyapp/services/wallet-service/internal/config"
|
|
)
|
|
|
|
type repeatedFlag []string
|
|
|
|
func (values *repeatedFlag) String() string { return strings.Join(*values, ",") }
|
|
|
|
func (values *repeatedFlag) Set(value string) error {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return errors.New("event-type cannot be empty")
|
|
}
|
|
*values = append(*values, value)
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
configPath := flag.String("config", "services/wallet-service/configs/config.yaml", "path to wallet-service config")
|
|
appCode := flag.String("app-code", "", "exact App partition to replay")
|
|
limit := flag.Int("limit", 0, "process-wide maximum rows, 1..500")
|
|
execute := flag.Bool("execute", false, "publish the bounded batch; default is a no-write dry-run")
|
|
confirmation := flag.String("confirm", "", "required execution confirmation")
|
|
timeout := flag.Duration("timeout", 2*time.Minute, "total command timeout, at most 30m")
|
|
var eventTypes repeatedFlag
|
|
flag.Var(&eventTypes, "event-type", "exact wallet event type to include; repeat for multiple types")
|
|
flag.Parse()
|
|
|
|
scope, err := outboxreplay.NewScope(*appCode, *limit, 500)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
if *timeout <= 0 || *timeout > 30*time.Minute {
|
|
fatal(errors.New("timeout must be within (0,30m]"))
|
|
}
|
|
if *execute && strings.TrimSpace(*confirmation) != outboxreplay.ExecuteConfirmation {
|
|
fatal(fmt.Errorf("--execute requires --confirm=%s", outboxreplay.ExecuteConfirmation))
|
|
}
|
|
cfg, err := config.Load(strings.TrimSpace(*configPath))
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
normalizedTypes, err := app.ValidateWalletReplayEventTypes(cfg, eventTypes)
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
if !*execute {
|
|
fmt.Printf("mode=dry-run app_code=%s limit=%d event_types=%s no_writes=true\n", scope.AppCode, scope.Limit, strings.Join(normalizedTypes, ","))
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
|
|
defer cancel()
|
|
result, err := app.ReplayWalletOutboxOnce(ctx, cfg, scope, normalizedTypes)
|
|
if err != nil {
|
|
fatal(fmt.Errorf("wallet replay stopped after %d rows: %w", result.Processed, err))
|
|
}
|
|
fmt.Printf("mode=execute app_code=%s limit=%d processed=%d drained=%t event_types=%s\n", scope.AppCode, scope.Limit, result.Processed, result.Drained, strings.Join(normalizedTypes, ","))
|
|
}
|
|
|
|
func fatal(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|