2
0
mirror of https://github.com/hibiken/asynq.git synced 2024-12-25 23:32:17 +08:00

(cli): Improve help command output

This commit is contained in:
Ken Hibino 2022-05-06 16:18:40 -07:00 committed by GitHub
parent 9116c096ec
commit 4dd2b5738a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 425 additions and 107 deletions

View File

@ -11,6 +11,7 @@ import (
"sort"
"time"
"github.com/MakeNowJust/heredoc/v2"
"github.com/hibiken/asynq"
"github.com/spf13/cobra"
)
@ -24,21 +25,30 @@ func init() {
}
var cronCmd = &cobra.Command{
Use: "cron",
Use: "cron <command> [flags]",
Short: "Manage cron",
Example: heredoc.Doc(`
$ asynq cron ls
$ asynq cron history 7837f142-6337-4217-9276-8f27281b67d1`),
}
var cronListCmd = &cobra.Command{
Use: "ls",
Short: "List cron entries",
Run: cronList,
Use: "list",
Aliases: []string{"ls"},
Short: "List cron entries",
Run: cronList,
}
var cronHistoryCmd = &cobra.Command{
Use: "history [ENTRY_ID...]",
Use: "history <entry_id> [<entry_id>...]",
Short: "Show history of each cron tasks",
Args: cobra.MinimumNArgs(1),
Run: cronHistory,
Example: heredoc.Doc(`
$ asynq cron history 7837f142-6337-4217-9276-8f27281b67d1
$ asynq cron history 7837f142-6337-4217-9276-8f27281b67d1 bf6a8594-cd03-4968-b36a-8572c5e160dd
$ asynq cron history 7837f142-6337-4217-9276-8f27281b67d1 --size=100
$ asynq cron history 7837f142-6337-4217-9276-8f27281b67d1 --page=2`),
}
func cronList(cmd *cobra.Command, args []string) {

View File

@ -8,6 +8,7 @@ import (
"fmt"
"os"
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"
)
@ -19,15 +20,18 @@ func init() {
}
var groupCmd = &cobra.Command{
Use: "group",
Use: "group <command> [flags]",
Short: "Manage groups",
Example: heredoc.Doc(`
$ asynq group list --queue=myqueue`),
}
var groupListCmd = &cobra.Command{
Use: "ls",
Short: "List groups",
Args: cobra.NoArgs,
Run: groupLists,
Use: "list",
Aliases: []string{"ls"},
Short: "List groups",
Args: cobra.NoArgs,
Run: groupLists,
}
func groupLists(cmd *cobra.Command, args []string) {

View File

@ -9,6 +9,7 @@ import (
"io"
"os"
"github.com/MakeNowJust/heredoc/v2"
"github.com/fatih/color"
"github.com/hibiken/asynq"
"github.com/hibiken/asynq/internal/errors"
@ -31,51 +32,75 @@ func init() {
}
var queueCmd = &cobra.Command{
Use: "queue",
Use: "queue <command> [flags]",
Short: "Manage queues",
Example: heredoc.Doc(`
$ asynq queue ls
$ asynq queue inspect myqueue
$ asynq queue pause myqueue`),
}
var queueListCmd = &cobra.Command{
Use: "ls",
Short: "List queues",
Use: "list",
Short: "List queues",
Aliases: []string{"ls"},
// TODO: Use RunE instead?
Run: queueList,
}
var queueInspectCmd = &cobra.Command{
Use: "inspect QUEUE [QUEUE...]",
Use: "inspect <queue> [<queue>...]",
Short: "Display detailed information on one or more queues",
Args: cobra.MinimumNArgs(1),
// TODO: Use RunE instead?
Run: queueInspect,
Example: heredoc.Doc(`
$ asynq queue inspect myqueue
$ asynq queue inspect queue1 queue2 queue3`),
}
var queueHistoryCmd = &cobra.Command{
Use: "history QUEUE [QUEUE...]",
Use: "history <queue> [<queue>...]",
Short: "Display historical aggregate data from one or more queues",
Args: cobra.MinimumNArgs(1),
Run: queueHistory,
Example: heredoc.Doc(`
$ asynq queue history myqueue
$ asynq queue history queue1 queue2 queue3
$ asynq queue history myqueue --days=90`),
}
var queuePauseCmd = &cobra.Command{
Use: "pause QUEUE [QUEUE...]",
Use: "pause <queue> [<queue>...]",
Short: "Pause one or more queues",
Args: cobra.MinimumNArgs(1),
Run: queuePause,
Example: heredoc.Doc(`
$ asynq queue pause myqueue
$ asynq queue pause queue1 queue2 queue3`),
}
var queueUnpauseCmd = &cobra.Command{
Use: "unpause QUEUE [QUEUE...]",
Short: "Unpause one or more queues",
Args: cobra.MinimumNArgs(1),
Run: queueUnpause,
Use: "resume <queue> [<queue>...]",
Short: "Resume (unpause) one or more queues",
Args: cobra.MinimumNArgs(1),
Aliases: []string{"unpause"},
Run: queueUnpause,
Example: heredoc.Doc(`
$ asynq queue resume myqueue
$ asynq queue resume queue1 queue2 queue3`),
}
var queueRemoveCmd = &cobra.Command{
Use: "rm QUEUE [QUEUE...]",
Short: "Remove one or more queues",
Args: cobra.MinimumNArgs(1),
Run: queueRemove,
Use: "remove <queue> [<queue>...]",
Short: "Remove one or more queues",
Aliases: []string{"rm", "delete"},
Args: cobra.MinimumNArgs(1),
Run: queueRemove,
Example: heredoc.Doc(`
$ asynq queue rm myqueue
$ asynq queue rm queue1 queue2 queue3
$ asynq queue rm myqueue --force`),
}
func queueList(cmd *cobra.Command, args []string) {

View File

@ -14,11 +14,15 @@ import (
"unicode"
"unicode/utf8"
"github.com/MakeNowJust/heredoc/v2"
"github.com/fatih/color"
"github.com/go-redis/redis/v8"
"github.com/hibiken/asynq"
"github.com/hibiken/asynq/internal/base"
"github.com/hibiken/asynq/internal/rdb"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/exp/utf8string"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
@ -39,10 +43,22 @@ var (
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "asynq",
Short: "A monitoring tool for asynq queues",
Long: `Asynq is a montoring CLI to inspect tasks and queues managed by asynq.`,
Use: "asynq <command> <subcommand> [flags]",
Short: "Asynq CLI",
Long: `Command line tool to inspect tasks and queues managed by Asynq`,
Version: base.Version,
SilenceUsage: true,
SilenceErrors: true,
Example: heredoc.Doc(`
$ asynq stats
$ asynq queue pause myqueue
$ asynq task list --queue=myqueue --state=archived`),
Annotations: map[string]string{
"help:feedback": heredoc.Doc(`
Open an issue at https://github.com/hibiken/asynq/issues/new/choose`),
},
}
var versionOutput = fmt.Sprintf("asynq version %s\n", base.Version)
@ -64,22 +80,233 @@ func Execute() {
}
}
func isRootCmd(cmd *cobra.Command) bool {
return cmd != nil && !cmd.HasParent()
}
// displayLine represents a line displayed in the output as '<name> <desc>',
// where pad is used to pad the name from desc.
type displayLine struct {
name string
desc string
pad int // number of rpad
}
func (l *displayLine) String() string {
return rpad(l.name, l.pad) + l.desc
}
type displayLines []*displayLine
func (dls displayLines) String() string {
var lines []string
for _, dl := range dls {
lines = append(lines, dl.String())
}
return strings.Join(lines, "\n")
}
// Capitalize the first word in the given string.
func capitalize(s string) string {
str := utf8string.NewString(s)
if str.RuneCount() == 0 {
return ""
}
var b strings.Builder
b.WriteString(strings.ToUpper(string(str.At(0))))
b.WriteString(str.Slice(1, str.RuneCount()))
return b.String()
}
func rootHelpFunc(cmd *cobra.Command, args []string) {
// Display helpful error message when user mistypes a subcommand (e.g. 'asynq queue lst').
if isRootCmd(cmd.Parent()) && len(args) >= 2 && args[1] != "--help" && args[1] != "-h" {
printSubcommandSuggestions(cmd, args[1])
return
}
var lines []*displayLine
var commands []*displayLine
for _, c := range cmd.Commands() {
if c.Hidden || c.Short == "" || c.Name() == "help" {
continue
}
l := &displayLine{name: c.Name() + ":", desc: capitalize(c.Short)}
commands = append(commands, l)
lines = append(lines, l)
}
var localFlags []*displayLine
cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
l := &displayLine{name: "--" + f.Name, desc: capitalize(f.Usage)}
localFlags = append(localFlags, l)
lines = append(lines, l)
})
var inheritedFlags []*displayLine
cmd.InheritedFlags().VisitAll(func(f *pflag.Flag) {
l := &displayLine{name: "--" + f.Name, desc: capitalize(f.Usage)}
inheritedFlags = append(inheritedFlags, l)
lines = append(lines, l)
})
adjustPadding(lines...)
type helpEntry struct {
Title string
Body string
}
var helpEntries []*helpEntry
desc := cmd.Long
if desc == "" {
desc = cmd.Short
}
if desc != "" {
helpEntries = append(helpEntries, &helpEntry{"", desc})
}
helpEntries = append(helpEntries, &helpEntry{"USAGE", cmd.UseLine()})
if len(commands) > 0 {
helpEntries = append(helpEntries, &helpEntry{"COMMANDS", displayLines(commands).String()})
}
if cmd.LocalFlags().HasFlags() {
helpEntries = append(helpEntries, &helpEntry{"FLAGS", displayLines(localFlags).String()})
}
if cmd.InheritedFlags().HasFlags() {
helpEntries = append(helpEntries, &helpEntry{"INHERITED FLAGS", displayLines(inheritedFlags).String()})
}
if cmd.Example != "" {
helpEntries = append(helpEntries, &helpEntry{"EXAMPLES", cmd.Example})
}
helpEntries = append(helpEntries, &helpEntry{"LEARN MORE", heredoc.Doc(`
Use 'asynq <command> <subcommand> --help' for more information about a command.`)})
if s, ok := cmd.Annotations["help:feedback"]; ok {
helpEntries = append(helpEntries, &helpEntry{"FEEDBACK", s})
}
out := cmd.OutOrStdout()
bold := color.New(color.Bold)
for _, e := range helpEntries {
if e.Title != "" {
// If there is a title, add indentation to each line in the body
bold.Fprintln(out, e.Title)
fmt.Fprintln(out, indent(e.Body, 2 /* spaces */))
} else {
// If there is no title, print the body as is
fmt.Fprintln(out, e.Body)
}
fmt.Fprintln(out)
}
}
func rootUsageFunc(cmd *cobra.Command) error {
out := cmd.OutOrStdout()
fmt.Fprintf(out, "Usage: %s", cmd.UseLine())
if subcmds := cmd.Commands(); len(subcmds) > 0 {
fmt.Fprint(out, "\n\nAvailable commands:\n")
for _, c := range subcmds {
if c.Hidden {
continue
}
fmt.Fprintf(out, " %s\n", c.Name())
}
}
var localFlags []*displayLine
cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
localFlags = append(localFlags, &displayLine{name: "--" + f.Name, desc: capitalize(f.Usage)})
})
adjustPadding(localFlags...)
if len(localFlags) > 0 {
fmt.Fprint(out, "\n\nFlags:\n")
for _, l := range localFlags {
fmt.Fprintf(out, " %s\n", l.String())
}
}
return nil
}
func printSubcommandSuggestions(cmd *cobra.Command, arg string) {
out := cmd.OutOrStdout()
fmt.Fprintf(out, "unknown command %q for %q\n", arg, cmd.CommandPath())
if cmd.SuggestionsMinimumDistance <= 0 {
cmd.SuggestionsMinimumDistance = 2
}
candidates := cmd.SuggestionsFor(arg)
if len(candidates) > 0 {
fmt.Fprint(out, "\nDid you mean this?\n")
for _, c := range candidates {
fmt.Fprintf(out, "\t%s\n", c)
}
}
fmt.Fprintln(out)
rootUsageFunc(cmd)
}
func adjustPadding(lines ...*displayLine) {
// find the maximum width of the name
max := 0
for _, l := range lines {
if n := utf8.RuneCountInString(l.name); n > max {
max = n
}
}
for _, l := range lines {
l.pad = max
}
}
// rpad adds padding to the right of a string.
func rpad(s string, padding int) string {
tmpl := fmt.Sprintf("%%-%ds ", padding)
return fmt.Sprintf(tmpl, s)
}
// indent indents the given text by given spaces.
func indent(text string, space int) string {
if len(text) == 0 {
return ""
}
var b strings.Builder
indentation := strings.Repeat(" ", space)
lastRune := '\n'
for _, r := range text {
if lastRune == '\n' {
b.WriteString(indentation)
}
b.WriteRune(r)
lastRune = r
}
return b.String()
}
// dedent removes any indentation from the given text.
func dedent(text string) string {
lines := strings.Split(text, "\n")
var b strings.Builder
for _, l := range lines {
b.WriteString(strings.TrimLeftFunc(l, unicode.IsSpace))
b.WriteRune('\n')
}
return b.String()
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.SetHelpFunc(rootHelpFunc)
rootCmd.SetUsageFunc(rootUsageFunc)
rootCmd.AddCommand(versionCmd)
rootCmd.SetVersionTemplate(versionOutput)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file to set flag defaut values (default is $HOME/.asynq.yaml)")
rootCmd.PersistentFlags().StringVarP(&uri, "uri", "u", "127.0.0.1:6379", "redis server URI")
rootCmd.PersistentFlags().IntVarP(&db, "db", "n", 0, "redis database number (default is 0)")
rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "", "password to use when connecting to redis server")
rootCmd.PersistentFlags().BoolVar(&useRedisCluster, "cluster", false, "connect to redis cluster")
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "Config file to set flag defaut values (default is $HOME/.asynq.yaml)")
rootCmd.PersistentFlags().StringVarP(&uri, "uri", "u", "127.0.0.1:6379", "Redis server URI")
rootCmd.PersistentFlags().IntVarP(&db, "db", "n", 0, "Redis database number (default is 0)")
rootCmd.PersistentFlags().StringVarP(&password, "password", "p", "", "Password to use when connecting to redis server")
rootCmd.PersistentFlags().BoolVar(&useRedisCluster, "cluster", false, "Connect to redis cluster")
rootCmd.PersistentFlags().StringVar(&clusterAddrs, "cluster_addrs",
"127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003,127.0.0.1:7004,127.0.0.1:7005",
"list of comma-separated redis server addresses")
"List of comma-separated redis server addresses")
rootCmd.PersistentFlags().StringVar(&tlsServerName, "tls_server",
"", "server name for TLS validation")
"", "Server name for TLS validation")
// Bind flags with config.
viper.BindPFlag("uri", rootCmd.PersistentFlags().Lookup("uri"))
viper.BindPFlag("db", rootCmd.PersistentFlags().Lookup("db"))

View File

@ -12,6 +12,7 @@ import (
"strings"
"time"
"github.com/MakeNowJust/heredoc/v2"
"github.com/spf13/cobra"
)
@ -21,13 +22,16 @@ func init() {
}
var serverCmd = &cobra.Command{
Use: "server",
Use: "server <command> [flags]",
Short: "Manage servers",
Example: heredoc.Doc(`
$ asynq server list`),
}
var serverListCmd = &cobra.Command{
Use: "ls",
Short: "List servers",
Use: "list",
Aliases: []string{"ls"},
Short: "List servers",
Long: `Server list (asynq server ls) shows all running worker servers
pulling tasks from the given redis instance.

View File

@ -16,6 +16,7 @@ import (
"time"
"unicode/utf8"
"github.com/MakeNowJust/heredoc/v2"
"github.com/fatih/color"
"github.com/hibiken/asynq/internal/rdb"
"github.com/spf13/cobra"
@ -24,19 +25,15 @@ import (
// statsCmd represents the stats command
var statsCmd = &cobra.Command{
Use: "stats",
Short: "Shows current state of the tasks and queues",
Long: `Stats (aysnq stats) will show the overview of tasks and queues at that instant.
Short: "View current state",
Long: heredoc.Doc(`
Stats shows the overview of tasks and queues at that instant.
Specifically, the command shows the following:
* Number of tasks in each state
* Number of tasks in each queue
* Aggregate data for the current day
* Basic information about the running redis instance
To monitor the tasks continuously, it's recommended that you run this
command in conjunction with the watch command.
Example: watch -n 3 asynq stats -> Shows current state of tasks every three seconds`,
The command shows the following:
* Number of tasks in each state
* Number of tasks in each queue
* Aggregate data for the current day
* Basic information about the running redis instance`),
Args: cobra.NoArgs,
Run: stats,
}

View File

@ -10,6 +10,7 @@ import (
"os"
"time"
"github.com/MakeNowJust/heredoc/v2"
"github.com/fatih/color"
"github.com/hibiken/asynq"
"github.com/spf13/cobra"
@ -18,8 +19,8 @@ import (
func init() {
rootCmd.AddCommand(taskCmd)
taskCmd.AddCommand(taskListCmd)
taskListCmd.Flags().StringP("queue", "q", "", "queue to inspect")
taskListCmd.Flags().StringP("state", "s", "", "state of the tasks to inspect")
taskListCmd.Flags().StringP("queue", "q", "", "queue to inspect (required)")
taskListCmd.Flags().StringP("state", "s", "", "state of the tasks; one of { active | pending | aggregating | scheduled | retry | archived | completed } (required)")
taskListCmd.Flags().Int("page", 1, "page number")
taskListCmd.Flags().Int("size", 30, "page size")
taskListCmd.Flags().StringP("group", "g", "", "group to inspect (required for listing aggregating tasks)")
@ -29,141 +30,155 @@ func init() {
taskCmd.AddCommand(taskCancelCmd)
taskCmd.AddCommand(taskInspectCmd)
taskInspectCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs")
taskInspectCmd.Flags().StringP("id", "i", "", "id of the task")
taskInspectCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs (required)")
taskInspectCmd.Flags().StringP("id", "i", "", "id of the task (required)")
taskInspectCmd.MarkFlagRequired("queue")
taskInspectCmd.MarkFlagRequired("id")
taskCmd.AddCommand(taskArchiveCmd)
taskArchiveCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs")
taskArchiveCmd.Flags().StringP("id", "i", "", "id of the task")
taskArchiveCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs (required)")
taskArchiveCmd.Flags().StringP("id", "i", "", "id of the task (required)")
taskArchiveCmd.MarkFlagRequired("queue")
taskArchiveCmd.MarkFlagRequired("id")
taskCmd.AddCommand(taskDeleteCmd)
taskDeleteCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs")
taskDeleteCmd.Flags().StringP("id", "i", "", "id of the task")
taskDeleteCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs (required)")
taskDeleteCmd.Flags().StringP("id", "i", "", "id of the task (required)")
taskDeleteCmd.MarkFlagRequired("queue")
taskDeleteCmd.MarkFlagRequired("id")
taskCmd.AddCommand(taskRunCmd)
taskRunCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs")
taskRunCmd.Flags().StringP("id", "i", "", "id of the task")
taskRunCmd.Flags().StringP("queue", "q", "", "queue to which the task belongs (required)")
taskRunCmd.Flags().StringP("id", "i", "", "id of the task (required)")
taskRunCmd.MarkFlagRequired("queue")
taskRunCmd.MarkFlagRequired("id")
taskCmd.AddCommand(taskArchiveAllCmd)
taskArchiveAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong")
taskArchiveAllCmd.Flags().StringP("state", "s", "", "state of the tasks")
taskArchiveAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong (required)")
taskArchiveAllCmd.Flags().StringP("state", "s", "", "state of the tasks; one of { pending | aggregating | scheduled | retry } (required)")
taskArchiveAllCmd.MarkFlagRequired("queue")
taskArchiveAllCmd.MarkFlagRequired("state")
taskArchiveAllCmd.Flags().StringP("group", "g", "", "group to which the tasks belong (required for archiving aggregating tasks)")
taskCmd.AddCommand(taskDeleteAllCmd)
taskDeleteAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong")
taskDeleteAllCmd.Flags().StringP("state", "s", "", "state of the tasks")
taskDeleteAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong (required)")
taskDeleteAllCmd.Flags().StringP("state", "s", "", "state of the tasks; one of { pending | aggregating | scheduled | retry | archived | completed } (required)")
taskDeleteAllCmd.MarkFlagRequired("queue")
taskDeleteAllCmd.MarkFlagRequired("state")
taskDeleteAllCmd.Flags().StringP("group", "g", "", "group to which the tasks belong (required for deleting aggregating tasks)")
taskCmd.AddCommand(taskRunAllCmd)
taskRunAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong")
taskRunAllCmd.Flags().StringP("state", "s", "", "state of the tasks")
taskRunAllCmd.Flags().StringP("queue", "q", "", "queue to which the tasks belong (required)")
taskRunAllCmd.Flags().StringP("state", "s", "", "state of the tasks; one of { scheduled | retry | archived } (required)")
taskRunAllCmd.MarkFlagRequired("queue")
taskRunAllCmd.MarkFlagRequired("state")
taskRunAllCmd.Flags().StringP("group", "g", "", "group to which the tasks belong (required for running aggregating tasks)")
}
var taskCmd = &cobra.Command{
Use: "task",
Use: "task <command> [flags]",
Short: "Manage tasks",
Example: heredoc.Doc(`
$ asynq task list --queue=myqueue --state=scheduled
$ asynq task inspect --queue=myqueue --id=7837f142-6337-4217-9276-8f27281b67d1
$ asynq task delete --queue=myqueue --id=7837f142-6337-4217-9276-8f27281b67d1
$ asynq task deleteall --queue=myqueue --state=archived`),
}
var taskListCmd = &cobra.Command{
Use: "ls --queue=QUEUE --state=STATE",
Short: "List tasks",
Long: `List tasks of the given state from the specified queue.
Use: "list --queue=<queue> --state=<state> [flags]",
Aliases: []string{"ls"},
Short: "List tasks",
Long: heredoc.Doc(`
List tasks of the given state from the specified queue.
The value for the state flag should be one of:
- active
- pending
- aggregating
- scheduled
- retry
- archived
- completed
The --queue and --state flags are required.
List opeartion paginates the result set.
By default, the command fetches the first 30 tasks.
Use --page and --size flags to specify the page number and size.
Note: For aggregating tasks, additional --group flag is required.
Example:
To list pending tasks from "default" queue, run
asynq task ls --queue=default --state=pending
To list the tasks from the second page, run
asynq task ls --queue=default --state=pending --page=1
For aggregating tasks, additional --group flag is required.
Example:
asynq task ls --queue=default --state=aggregating --group=mygroup
`,
List opeartion paginates the result set. By default, the command fetches the first 30 tasks.
Use --page and --size flags to specify the page number and size.`),
Example: heredoc.Doc(`
$ asynq task list --queue=myqueue --state=pending
$ asynq task list --queue=myqueue --state=aggregating --group=mygroup
$ asynq task list --queue=myqueue --state=scheduled --page=2`),
Run: taskList,
}
var taskInspectCmd = &cobra.Command{
Use: "inspect --queue=QUEUE --id=TASK_ID",
Use: "inspect --queue=<queue> --id=<task_id>",
Short: "Display detailed information on the specified task",
Args: cobra.NoArgs,
Run: taskInspect,
Example: heredoc.Doc(`
$ asynq task inspect --queue=myqueue --id=f1720682-f5a6-4db1-8953-4f48ae541d0f`),
}
var taskCancelCmd = &cobra.Command{
Use: "cancel TASK_ID [TASK_ID...]",
Use: "cancel <task_id> [<task_id>...]",
Short: "Cancel one or more active tasks",
Args: cobra.MinimumNArgs(1),
Run: taskCancel,
Example: heredoc.Doc(`
$ asynq task cancel f1720682-f5a6-4db1-8953-4f48ae541d0f`),
}
var taskArchiveCmd = &cobra.Command{
Use: "archive --queue=QUEUE --id=TASK_ID",
Use: "archive --queue=<queue> --id=<task_id>",
Short: "Archive a task with the given id",
Args: cobra.NoArgs,
Run: taskArchive,
Example: heredoc.Doc(`
$ asynq task archive --queue=myqueue --id=f1720682-f5a6-4db1-8953-4f48ae541d0f`),
}
var taskDeleteCmd = &cobra.Command{
Use: "delete --queue=QUEUE --id=TASK_ID",
Short: "Delete a task with the given id",
Args: cobra.NoArgs,
Run: taskDelete,
Use: "delete --queue=<queue> --id=<task_id>",
Aliases: []string{"remove", "rm"},
Short: "Delete a task with the given id",
Args: cobra.NoArgs,
Run: taskDelete,
Example: heredoc.Doc(`
$ asynq task delete --queue=myqueue --id=f1720682-f5a6-4db1-8953-4f48ae541d0f`),
}
var taskRunCmd = &cobra.Command{
Use: "run --queue=QUEUE --id=TASK_ID",
Use: "run --queue=<queue> --id=<task_id>",
Short: "Run a task with the given id",
Args: cobra.NoArgs,
Run: taskRun,
Example: heredoc.Doc(`
$ asynq task run --queue=myqueue --id=f1720682-f5a6-4db1-8953-4f48ae541d0f`),
}
var taskArchiveAllCmd = &cobra.Command{
Use: "archiveall --queue=QUEUE --state=STATE",
Use: "archiveall --queue=<queue> --state=<state>",
Short: "Archive all tasks in the given state",
Args: cobra.NoArgs,
Run: taskArchiveAll,
Example: heredoc.Doc(`
$ asynq task archiveall --queue=myqueue --state=retry
$ asynq task archiveall --queue=myqueue --state=aggregating --group=mygroup`),
}
var taskDeleteAllCmd = &cobra.Command{
Use: "deleteall --queue=QUEUE --state=STATE",
Use: "deleteall --queue=<queue> --state=<state>",
Short: "Delete all tasks in the given state",
Args: cobra.NoArgs,
Run: taskDeleteAll,
Example: heredoc.Doc(`
$ asynq task deleteall --queue=myqueue --state=archived
$ asynq task deleteall --queue=myqueue --state=aggregating --group=mygroup`),
}
var taskRunAllCmd = &cobra.Command{
Use: "runall --queue=QUEUE --state=STATE",
Use: "runall --queue=<queue> --state=<state>",
Short: "Run all tasks in the given state",
Args: cobra.NoArgs,
Run: taskRunAll,
Example: heredoc.Doc(`
$ asynq task runall --queue=myqueue --state=retry
$ asynq task runall --queue=myqueue --state=aggregating --group=mygroup`),
}
func taskList(cmd *cobra.Command, args []string) {
@ -527,6 +542,17 @@ func taskArchiveAll(cmd *cobra.Command, args []string) {
n, err = i.ArchiveAllScheduledTasks(qname)
case "retry":
n, err = i.ArchiveAllRetryTasks(qname)
case "aggregating":
group, err := cmd.Flags().GetString("group")
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
if group == "" {
fmt.Println("error: Flag --group is required for aggregating tasks")
os.Exit(1)
}
n, err = i.ArchiveAllAggregatingTasks(qname, group)
default:
fmt.Printf("error: unsupported state %q\n", state)
os.Exit(1)
@ -563,6 +589,17 @@ func taskDeleteAll(cmd *cobra.Command, args []string) {
n, err = i.DeleteAllArchivedTasks(qname)
case "completed":
n, err = i.DeleteAllCompletedTasks(qname)
case "aggregating":
group, err := cmd.Flags().GetString("group")
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
if group == "" {
fmt.Println("error: Flag --group is required for aggregating tasks")
os.Exit(1)
}
n, err = i.DeleteAllAggregatingTasks(qname, group)
default:
fmt.Printf("error: unsupported state %q\n", state)
os.Exit(1)
@ -595,6 +632,17 @@ func taskRunAll(cmd *cobra.Command, args []string) {
n, err = i.RunAllRetryTasks(qname)
case "archived":
n, err = i.RunAllArchivedTasks(qname)
case "aggregating":
group, err := cmd.Flags().GetString("group")
if err != nil {
fmt.Printf("error: %v\n", err)
os.Exit(1)
}
if group == "" {
fmt.Println("error: Flag --group is required for aggregating tasks")
os.Exit(1)
}
n, err = i.RunAllAggregatingTasks(qname, group)
default:
fmt.Printf("error: unsupported state %q\n", state)
os.Exit(1)

View File

@ -3,13 +3,15 @@ module github.com/hibiken/asynq/tools
go 1.13
require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/fatih/color v1.9.0
github.com/go-redis/redis/v8 v8.11.4
github.com/hibiken/asynq v0.23.0
github.com/hibiken/asynq/x v0.0.0-20220131170841-349f4c50fb1d
github.com/mitchellh/go-homedir v1.1.0
github.com/prometheus/client_golang v1.11.0
github.com/spf13/afero v1.1.2 // indirect
github.com/spf13/cobra v1.1.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136
)

View File

@ -14,6 +14,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/MakeNowJust/heredoc/v2 v2.0.1 h1:rlCHh70XXXv7toz95ajQWOWQnN4WNLt0TdpZYIR/J6A=
github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRrqsyY9MWy+4JdRM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -140,8 +142,6 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hibiken/asynq v0.19.0/go.mod h1:tyc63ojaW8SJ5SBm8mvI4DDONsguP5HE85EEl4Qr5Ig=
github.com/hibiken/asynq v0.21.0 h1:uH9XogJhjq/S39E0/DEPWLZQ6hHJ73UiblZTe4RzHwA=
github.com/hibiken/asynq v0.21.0/go.mod h1:tyc63ojaW8SJ5SBm8mvI4DDONsguP5HE85EEl4Qr5Ig=
github.com/hibiken/asynq v0.23.0 h1:kmKkNFgqiXBatC8oz94Mer6uvKoGn4STlIVDV5wnKyE=
github.com/hibiken/asynq v0.23.0/go.mod h1:K70jPVx+CAmmQrXot7Dru0D52EO7ob4BIun3ri5z1Qw=
github.com/hibiken/asynq/x v0.0.0-20220131170841-349f4c50fb1d h1:Er+U+9PmnyRHRDQjSjRQ24HoWvOY7w9Pk7bUPYM3Ags=
@ -307,6 +307,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=