// Command replay-outbox publishes a hard-bounded user owner-outbox batch for // one App without starting the user-service API or unrelated MQ consumers. package main import ( "context" "errors" "flag" "fmt" "os" "strings" "time" "hyapp/pkg/outboxreplay" "hyapp/services/user-service/internal/app" "hyapp/services/user-service/internal/config" ) func main() { configPath := flag.String("config", "services/user-service/configs/config.yaml", "path to user-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") 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) } if !*execute { fmt.Printf("mode=dry-run app_code=%s limit=%d no_writes=true\n", scope.AppCode, scope.Limit) return } ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() result, err := app.ReplayUserOutboxOnce(ctx, cfg, scope) if err != nil { fatal(fmt.Errorf("user replay stopped after %d rows: %w", result.Processed, err)) } fmt.Printf("mode=execute app_code=%s limit=%d processed=%d drained=%t\n", scope.AppCode, scope.Limit, result.Processed, result.Drained) } func fatal(err error) { fmt.Fprintln(os.Stderr, err) os.Exit(1) }