github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/inspector.go (about)

     1  // Copyright 2020 Kentaro Hibino. All rights reserved.
     2  // Use of this source code is governed by a MIT license
     3  // that can be found in the LICENSE file.
     4  
     5  package asynq
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/redis/go-redis/v9"
    14  	"github.com/wfusion/gofusion/common/infra/asynq/pkg/base"
    15  	"github.com/wfusion/gofusion/common/infra/asynq/pkg/errors"
    16  	"github.com/wfusion/gofusion/common/infra/asynq/pkg/rdb"
    17  )
    18  
    19  // Inspector is a client interface to inspect and mutate the state of
    20  // queues and tasks.
    21  type Inspector struct {
    22  	rdb *rdb.RDB
    23  }
    24  
    25  // NewInspector returns a new instance of Inspector.
    26  func NewInspector(r RedisConnOpt) *Inspector {
    27  	c, ok := r.MakeRedisClient().(redis.UniversalClient)
    28  	if !ok {
    29  		panic(fmt.Sprintf("inspeq: unsupported RedisConnOpt type %T", r))
    30  	}
    31  	return &Inspector{
    32  		rdb: rdb.NewRDB(c),
    33  	}
    34  }
    35  
    36  // Close closes the connection with redis.
    37  func (i *Inspector) Close() error {
    38  	return i.rdb.Close()
    39  }
    40  
    41  // Queues returns a list of all queue names.
    42  func (i *Inspector) Queues() ([]string, error) {
    43  	return i.rdb.AllQueues()
    44  }
    45  
    46  // Groups returns a list of all groups within the given queue.
    47  func (i *Inspector) Groups(queue string) ([]*GroupInfo, error) {
    48  	stats, err := i.rdb.GroupStats(queue)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	var res []*GroupInfo
    53  	for _, s := range stats {
    54  		res = append(res, &GroupInfo{
    55  			Group: s.Group,
    56  			Size:  s.Size,
    57  		})
    58  	}
    59  	return res, nil
    60  }
    61  
    62  // GroupInfo represents a state of a group at a certain time.
    63  type GroupInfo struct {
    64  	// Name of the group.
    65  	Group string
    66  
    67  	// Size is the total number of tasks in the group.
    68  	Size int
    69  }
    70  
    71  // QueueInfo represents a state of a queue at a certain time.
    72  type QueueInfo struct {
    73  	// Name of the queue.
    74  	Queue string
    75  
    76  	// Total number of bytes that the queue and its tasks require to be stored in redis.
    77  	// It is an approximate memory usage value in bytes since the value is computed by sampling.
    78  	MemoryUsage int64
    79  
    80  	// Latency of the queue, measured by the oldest pending task in the queue.
    81  	Latency time.Duration
    82  
    83  	// Size is the total number of tasks in the queue.
    84  	// The value is the sum of Pending, Active, Scheduled, Retry, Aggregating and Archived.
    85  	Size int
    86  
    87  	// Groups is the total number of groups in the queue.
    88  	Groups int
    89  
    90  	// Number of pending tasks.
    91  	Pending int
    92  	// Number of active tasks.
    93  	Active int
    94  	// Number of scheduled tasks.
    95  	Scheduled int
    96  	// Number of retry tasks.
    97  	Retry int
    98  	// Number of archived tasks.
    99  	Archived int
   100  	// Number of stored completed tasks.
   101  	Completed int
   102  	// Number of aggregating tasks.
   103  	Aggregating int
   104  
   105  	// Total number of tasks being processed within the given date (counter resets daily).
   106  	// The number includes both succeeded and failed tasks.
   107  	Processed int
   108  	// Total number of tasks failed to be processed within the given date (counter resets daily).
   109  	Failed int
   110  
   111  	// Total number of tasks processed (cumulative).
   112  	ProcessedTotal int
   113  	// Total number of tasks failed (cumulative).
   114  	FailedTotal int
   115  
   116  	// Paused indicates whether the queue is paused.
   117  	// If true, tasks in the queue will not be processed.
   118  	Paused bool
   119  
   120  	// Time when this queue info snapshot was taken.
   121  	Timestamp time.Time
   122  }
   123  
   124  // GetQueueInfo returns current information of the given queue.
   125  func (i *Inspector) GetQueueInfo(queue string) (*QueueInfo, error) {
   126  	if err := base.ValidateQueueName(queue); err != nil {
   127  		return nil, err
   128  	}
   129  	stats, err := i.rdb.CurrentStats(queue)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	return &QueueInfo{
   134  		Queue:          stats.Queue,
   135  		MemoryUsage:    stats.MemoryUsage,
   136  		Latency:        stats.Latency,
   137  		Size:           stats.Size,
   138  		Groups:         stats.Groups,
   139  		Pending:        stats.Pending,
   140  		Active:         stats.Active,
   141  		Scheduled:      stats.Scheduled,
   142  		Retry:          stats.Retry,
   143  		Archived:       stats.Archived,
   144  		Completed:      stats.Completed,
   145  		Aggregating:    stats.Aggregating,
   146  		Processed:      stats.Processed,
   147  		Failed:         stats.Failed,
   148  		ProcessedTotal: stats.ProcessedTotal,
   149  		FailedTotal:    stats.FailedTotal,
   150  		Paused:         stats.Paused,
   151  		Timestamp:      stats.Timestamp,
   152  	}, nil
   153  }
   154  
   155  // DailyStats holds aggregate data for a given day for a given queue.
   156  type DailyStats struct {
   157  	// Name of the queue.
   158  	Queue string
   159  	// Total number of tasks being processed during the given date.
   160  	// The number includes both succeeded and failed tasks.
   161  	Processed int
   162  	// Total number of tasks failed to be processed during the given date.
   163  	Failed int
   164  	// Date this stats was taken.
   165  	Date time.Time
   166  }
   167  
   168  // History returns a list of stats from the last n days.
   169  func (i *Inspector) History(queue string, n int) ([]*DailyStats, error) {
   170  	if err := base.ValidateQueueName(queue); err != nil {
   171  		return nil, err
   172  	}
   173  	stats, err := i.rdb.HistoricalStats(queue, n)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	var res []*DailyStats
   178  	for _, s := range stats {
   179  		res = append(res, &DailyStats{
   180  			Queue:     s.Queue,
   181  			Processed: s.Processed,
   182  			Failed:    s.Failed,
   183  			Date:      s.Time,
   184  		})
   185  	}
   186  	return res, nil
   187  }
   188  
   189  var (
   190  	// ErrQueueNotFound indicates that the specified queue does not exist.
   191  	ErrQueueNotFound = errors.New("queue not found")
   192  
   193  	// ErrQueueNotEmpty indicates that the specified queue is not empty.
   194  	ErrQueueNotEmpty = errors.New("queue is not empty")
   195  
   196  	// ErrTaskNotFound indicates that the specified task cannot be found in the queue.
   197  	ErrTaskNotFound = errors.New("task not found")
   198  )
   199  
   200  // DeleteQueue removes the specified queue.
   201  //
   202  // If force is set to true, DeleteQueue will remove the queue regardless of
   203  // the queue size as long as no tasks are active in the queue.
   204  // If force is set to false, DeleteQueue will remove the queue only if
   205  // the queue is empty.
   206  //
   207  // If the specified queue does not exist, DeleteQueue returns ErrQueueNotFound.
   208  // If force is set to false and the specified queue is not empty, DeleteQueue
   209  // returns ErrQueueNotEmpty.
   210  func (i *Inspector) DeleteQueue(queue string, force bool) error {
   211  	err := i.rdb.RemoveQueue(queue, force)
   212  	if errors.IsQueueNotFound(err) {
   213  		return fmt.Errorf("%w: queue=%q", ErrQueueNotFound, queue)
   214  	}
   215  	if errors.IsQueueNotEmpty(err) {
   216  		return fmt.Errorf("%w: queue=%q", ErrQueueNotEmpty, queue)
   217  	}
   218  	return err
   219  }
   220  
   221  // GetTaskInfo retrieves task information given a task id and queue name.
   222  //
   223  // Returns an error wrapping ErrQueueNotFound if a queue with the given name doesn't exist.
   224  // Returns an error wrapping ErrTaskNotFound if a task with the given id doesn't exist in the queue.
   225  func (i *Inspector) GetTaskInfo(queue, id string) (*TaskInfo, error) {
   226  	info, err := i.rdb.GetTaskInfo(queue, id)
   227  	switch {
   228  	case errors.IsQueueNotFound(err):
   229  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   230  	case errors.IsTaskNotFound(err):
   231  		return nil, fmt.Errorf("asynq: %w", ErrTaskNotFound)
   232  	case err != nil:
   233  		return nil, fmt.Errorf("asynq: %v", err)
   234  	}
   235  	return newTaskInfo(info.Message, info.State, info.NextProcessAt, info.Result), nil
   236  }
   237  
   238  // ListOption specifies behavior of list operation.
   239  type ListOption any
   240  
   241  // Internal list option representations.
   242  type (
   243  	pageSizeOpt int
   244  	pageNumOpt  int
   245  )
   246  
   247  type listOption struct {
   248  	pageSize int
   249  	pageNum  int
   250  }
   251  
   252  const (
   253  	// Page size used by default in list operation.
   254  	defaultPageSize = 30
   255  
   256  	// Page number used by default in list operation.
   257  	defaultPageNum = 1
   258  )
   259  
   260  func composeListOptions(opts ...ListOption) listOption {
   261  	res := listOption{
   262  		pageSize: defaultPageSize,
   263  		pageNum:  defaultPageNum,
   264  	}
   265  	for _, opt := range opts {
   266  		switch opt := opt.(type) {
   267  		case pageSizeOpt:
   268  			res.pageSize = int(opt)
   269  		case pageNumOpt:
   270  			res.pageNum = int(opt)
   271  		default:
   272  			// ignore unexpected option
   273  		}
   274  	}
   275  	return res
   276  }
   277  
   278  // PageSize returns an option to specify the page size for list operation.
   279  //
   280  // Negative page size is treated as zero.
   281  func PageSize(n int) ListOption {
   282  	if n < 0 {
   283  		n = 0
   284  	}
   285  	return pageSizeOpt(n)
   286  }
   287  
   288  // Page returns an option to specify the page number for list operation.
   289  // The value 1 fetches the first page.
   290  //
   291  // Negative page number is treated as one.
   292  func Page(n int) ListOption {
   293  	if n < 0 {
   294  		n = 1
   295  	}
   296  	return pageNumOpt(n)
   297  }
   298  
   299  // ListPendingTasks retrieves pending tasks from the specified queue.
   300  //
   301  // By default, it retrieves the first 30 tasks.
   302  func (i *Inspector) ListPendingTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   303  	if err := base.ValidateQueueName(queue); err != nil {
   304  		return nil, fmt.Errorf("asynq: %v", err)
   305  	}
   306  	opt := composeListOptions(opts...)
   307  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   308  	infos, err := i.rdb.ListPending(queue, pgn)
   309  	switch {
   310  	case errors.IsQueueNotFound(err):
   311  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   312  	case err != nil:
   313  		return nil, fmt.Errorf("asynq: %v", err)
   314  	}
   315  	var tasks []*TaskInfo
   316  	for _, i := range infos {
   317  		tasks = append(tasks, newTaskInfo(
   318  			i.Message,
   319  			i.State,
   320  			i.NextProcessAt,
   321  			i.Result,
   322  		))
   323  	}
   324  	return tasks, err
   325  }
   326  
   327  // ListActiveTasks retrieves active tasks from the specified queue.
   328  //
   329  // By default, it retrieves the first 30 tasks.
   330  func (i *Inspector) ListActiveTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   331  	if err := base.ValidateQueueName(queue); err != nil {
   332  		return nil, fmt.Errorf("asynq: %v", err)
   333  	}
   334  	opt := composeListOptions(opts...)
   335  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   336  	infos, err := i.rdb.ListActive(queue, pgn)
   337  	switch {
   338  	case errors.IsQueueNotFound(err):
   339  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   340  	case err != nil:
   341  		return nil, fmt.Errorf("asynq: %v", err)
   342  	}
   343  	expired, err := i.rdb.ListLeaseExpired(time.Now(), queue)
   344  	if err != nil {
   345  		return nil, fmt.Errorf("asynq: %v", err)
   346  	}
   347  	expiredSet := make(map[string]struct{}) // set of expired message IDs
   348  	for _, msg := range expired {
   349  		expiredSet[msg.ID] = struct{}{}
   350  	}
   351  	var tasks []*TaskInfo
   352  	for _, i := range infos {
   353  		t := newTaskInfo(
   354  			i.Message,
   355  			i.State,
   356  			i.NextProcessAt,
   357  			i.Result,
   358  		)
   359  		if _, ok := expiredSet[i.Message.ID]; ok {
   360  			t.IsOrphaned = true
   361  		}
   362  		tasks = append(tasks, t)
   363  	}
   364  	return tasks, nil
   365  }
   366  
   367  // ListAggregatingTasks retrieves scheduled tasks from the specified group.
   368  //
   369  // By default, it retrieves the first 30 tasks.
   370  func (i *Inspector) ListAggregatingTasks(queue, group string, opts ...ListOption) ([]*TaskInfo, error) {
   371  	if err := base.ValidateQueueName(queue); err != nil {
   372  		return nil, fmt.Errorf("asynq: %v", err)
   373  	}
   374  	opt := composeListOptions(opts...)
   375  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   376  	infos, err := i.rdb.ListAggregating(queue, group, pgn)
   377  	switch {
   378  	case errors.IsQueueNotFound(err):
   379  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   380  	case err != nil:
   381  		return nil, fmt.Errorf("asynq: %v", err)
   382  	}
   383  	var tasks []*TaskInfo
   384  	for _, i := range infos {
   385  		tasks = append(tasks, newTaskInfo(
   386  			i.Message,
   387  			i.State,
   388  			i.NextProcessAt,
   389  			i.Result,
   390  		))
   391  	}
   392  	return tasks, nil
   393  }
   394  
   395  // ListScheduledTasks retrieves scheduled tasks from the specified queue.
   396  // Tasks are sorted by NextProcessAt in ascending order.
   397  //
   398  // By default, it retrieves the first 30 tasks.
   399  func (i *Inspector) ListScheduledTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   400  	if err := base.ValidateQueueName(queue); err != nil {
   401  		return nil, fmt.Errorf("asynq: %v", err)
   402  	}
   403  	opt := composeListOptions(opts...)
   404  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   405  	infos, err := i.rdb.ListScheduled(queue, pgn)
   406  	switch {
   407  	case errors.IsQueueNotFound(err):
   408  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   409  	case err != nil:
   410  		return nil, fmt.Errorf("asynq: %v", err)
   411  	}
   412  	var tasks []*TaskInfo
   413  	for _, i := range infos {
   414  		tasks = append(tasks, newTaskInfo(
   415  			i.Message,
   416  			i.State,
   417  			i.NextProcessAt,
   418  			i.Result,
   419  		))
   420  	}
   421  	return tasks, nil
   422  }
   423  
   424  // ListRetryTasks retrieves retry tasks from the specified queue.
   425  // Tasks are sorted by NextProcessAt in ascending order.
   426  //
   427  // By default, it retrieves the first 30 tasks.
   428  func (i *Inspector) ListRetryTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   429  	if err := base.ValidateQueueName(queue); err != nil {
   430  		return nil, fmt.Errorf("asynq: %v", err)
   431  	}
   432  	opt := composeListOptions(opts...)
   433  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   434  	infos, err := i.rdb.ListRetry(queue, pgn)
   435  	switch {
   436  	case errors.IsQueueNotFound(err):
   437  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   438  	case err != nil:
   439  		return nil, fmt.Errorf("asynq: %v", err)
   440  	}
   441  	var tasks []*TaskInfo
   442  	for _, i := range infos {
   443  		tasks = append(tasks, newTaskInfo(
   444  			i.Message,
   445  			i.State,
   446  			i.NextProcessAt,
   447  			i.Result,
   448  		))
   449  	}
   450  	return tasks, nil
   451  }
   452  
   453  // ListArchivedTasks retrieves archived tasks from the specified queue.
   454  // Tasks are sorted by LastFailedAt in descending order.
   455  //
   456  // By default, it retrieves the first 30 tasks.
   457  func (i *Inspector) ListArchivedTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   458  	if err := base.ValidateQueueName(queue); err != nil {
   459  		return nil, fmt.Errorf("asynq: %v", err)
   460  	}
   461  	opt := composeListOptions(opts...)
   462  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   463  	infos, err := i.rdb.ListArchived(queue, pgn)
   464  	switch {
   465  	case errors.IsQueueNotFound(err):
   466  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   467  	case err != nil:
   468  		return nil, fmt.Errorf("asynq: %v", err)
   469  	}
   470  	var tasks []*TaskInfo
   471  	for _, i := range infos {
   472  		tasks = append(tasks, newTaskInfo(
   473  			i.Message,
   474  			i.State,
   475  			i.NextProcessAt,
   476  			i.Result,
   477  		))
   478  	}
   479  	return tasks, nil
   480  }
   481  
   482  // ListCompletedTasks retrieves completed tasks from the specified queue.
   483  // Tasks are sorted by expiration time (i.e. CompletedAt + Retention) in descending order.
   484  //
   485  // By default, it retrieves the first 30 tasks.
   486  func (i *Inspector) ListCompletedTasks(queue string, opts ...ListOption) ([]*TaskInfo, error) {
   487  	if err := base.ValidateQueueName(queue); err != nil {
   488  		return nil, fmt.Errorf("asynq: %v", err)
   489  	}
   490  	opt := composeListOptions(opts...)
   491  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
   492  	infos, err := i.rdb.ListCompleted(queue, pgn)
   493  	switch {
   494  	case errors.IsQueueNotFound(err):
   495  		return nil, fmt.Errorf("asynq: %w", ErrQueueNotFound)
   496  	case err != nil:
   497  		return nil, fmt.Errorf("asynq: %v", err)
   498  	}
   499  	var tasks []*TaskInfo
   500  	for _, i := range infos {
   501  		tasks = append(tasks, newTaskInfo(
   502  			i.Message,
   503  			i.State,
   504  			i.NextProcessAt,
   505  			i.Result,
   506  		))
   507  	}
   508  	return tasks, nil
   509  }
   510  
   511  // DeleteAllPendingTasks deletes all pending tasks from the specified queue,
   512  // and reports the number tasks deleted.
   513  func (i *Inspector) DeleteAllPendingTasks(queue string) (int, error) {
   514  	if err := base.ValidateQueueName(queue); err != nil {
   515  		return 0, err
   516  	}
   517  	n, err := i.rdb.DeleteAllPendingTasks(queue)
   518  	return int(n), err
   519  }
   520  
   521  // DeleteAllScheduledTasks deletes all scheduled tasks from the specified queue,
   522  // and reports the number tasks deleted.
   523  func (i *Inspector) DeleteAllScheduledTasks(queue string) (int, error) {
   524  	if err := base.ValidateQueueName(queue); err != nil {
   525  		return 0, err
   526  	}
   527  	n, err := i.rdb.DeleteAllScheduledTasks(queue)
   528  	return int(n), err
   529  }
   530  
   531  // DeleteAllRetryTasks deletes all retry tasks from the specified queue,
   532  // and reports the number tasks deleted.
   533  func (i *Inspector) DeleteAllRetryTasks(queue string) (int, error) {
   534  	if err := base.ValidateQueueName(queue); err != nil {
   535  		return 0, err
   536  	}
   537  	n, err := i.rdb.DeleteAllRetryTasks(queue)
   538  	return int(n), err
   539  }
   540  
   541  // DeleteAllArchivedTasks deletes all archived tasks from the specified queue,
   542  // and reports the number tasks deleted.
   543  func (i *Inspector) DeleteAllArchivedTasks(queue string) (int, error) {
   544  	if err := base.ValidateQueueName(queue); err != nil {
   545  		return 0, err
   546  	}
   547  	n, err := i.rdb.DeleteAllArchivedTasks(queue)
   548  	return int(n), err
   549  }
   550  
   551  // DeleteAllCompletedTasks deletes all completed tasks from the specified queue,
   552  // and reports the number tasks deleted.
   553  func (i *Inspector) DeleteAllCompletedTasks(queue string) (int, error) {
   554  	if err := base.ValidateQueueName(queue); err != nil {
   555  		return 0, err
   556  	}
   557  	n, err := i.rdb.DeleteAllCompletedTasks(queue)
   558  	return int(n), err
   559  }
   560  
   561  // DeleteAllAggregatingTasks deletes all tasks from the specified group,
   562  // and reports the number of tasks deleted.
   563  func (i *Inspector) DeleteAllAggregatingTasks(queue, group string) (int, error) {
   564  	if err := base.ValidateQueueName(queue); err != nil {
   565  		return 0, err
   566  	}
   567  	n, err := i.rdb.DeleteAllAggregatingTasks(queue, group)
   568  	return int(n), err
   569  }
   570  
   571  // DeleteTask deletes a task with the given id from the given queue.
   572  // The task needs to be in pending, scheduled, retry, or archived state,
   573  // otherwise DeleteTask will return an error.
   574  //
   575  // If a queue with the given name doesn't exist, it returns an error wrapping ErrQueueNotFound.
   576  // If a task with the given id doesn't exist in the queue, it returns an error wrapping ErrTaskNotFound.
   577  // If the task is in active state, it returns a non-nil error.
   578  func (i *Inspector) DeleteTask(queue, id string) error {
   579  	if err := base.ValidateQueueName(queue); err != nil {
   580  		return fmt.Errorf("asynq: %v", err)
   581  	}
   582  	err := i.rdb.DeleteTask(queue, id)
   583  	switch {
   584  	case errors.IsQueueNotFound(err):
   585  		return fmt.Errorf("asynq: %w", ErrQueueNotFound)
   586  	case errors.IsTaskNotFound(err):
   587  		return fmt.Errorf("asynq: %w", ErrTaskNotFound)
   588  	case err != nil:
   589  		return fmt.Errorf("asynq: %v", err)
   590  	}
   591  	return nil
   592  
   593  }
   594  
   595  // RunAllScheduledTasks schedules all scheduled tasks from the given queue to run,
   596  // and reports the number of tasks scheduled to run.
   597  func (i *Inspector) RunAllScheduledTasks(queue string) (int, error) {
   598  	if err := base.ValidateQueueName(queue); err != nil {
   599  		return 0, err
   600  	}
   601  	n, err := i.rdb.RunAllScheduledTasks(queue)
   602  	return int(n), err
   603  }
   604  
   605  // RunAllRetryTasks schedules all retry tasks from the given queue to run,
   606  // and reports the number of tasks scheduled to run.
   607  func (i *Inspector) RunAllRetryTasks(queue string) (int, error) {
   608  	if err := base.ValidateQueueName(queue); err != nil {
   609  		return 0, err
   610  	}
   611  	n, err := i.rdb.RunAllRetryTasks(queue)
   612  	return int(n), err
   613  }
   614  
   615  // RunAllArchivedTasks schedules all archived tasks from the given queue to run,
   616  // and reports the number of tasks scheduled to run.
   617  func (i *Inspector) RunAllArchivedTasks(queue string) (int, error) {
   618  	if err := base.ValidateQueueName(queue); err != nil {
   619  		return 0, err
   620  	}
   621  	n, err := i.rdb.RunAllArchivedTasks(queue)
   622  	return int(n), err
   623  }
   624  
   625  // RunAllAggregatingTasks schedules all tasks from the given grou to run.
   626  // and reports the number of tasks scheduled to run.
   627  func (i *Inspector) RunAllAggregatingTasks(queue, group string) (int, error) {
   628  	if err := base.ValidateQueueName(queue); err != nil {
   629  		return 0, err
   630  	}
   631  	n, err := i.rdb.RunAllAggregatingTasks(queue, group)
   632  	return int(n), err
   633  }
   634  
   635  // RunTask updates the task to pending state given a queue name and task id.
   636  // The task needs to be in scheduled, retry, or archived state, otherwise RunTask
   637  // will return an error.
   638  //
   639  // If a queue with the given name doesn't exist, it returns an error wrapping ErrQueueNotFound.
   640  // If a task with the given id doesn't exist in the queue, it returns an error wrapping ErrTaskNotFound.
   641  // If the task is in pending or active state, it returns a non-nil error.
   642  func (i *Inspector) RunTask(queue, id string) error {
   643  	if err := base.ValidateQueueName(queue); err != nil {
   644  		return fmt.Errorf("asynq: %v", err)
   645  	}
   646  	err := i.rdb.RunTask(queue, id)
   647  	switch {
   648  	case errors.IsQueueNotFound(err):
   649  		return fmt.Errorf("asynq: %w", ErrQueueNotFound)
   650  	case errors.IsTaskNotFound(err):
   651  		return fmt.Errorf("asynq: %w", ErrTaskNotFound)
   652  	case err != nil:
   653  		return fmt.Errorf("asynq: %v", err)
   654  	}
   655  	return nil
   656  }
   657  
   658  // ArchiveAllPendingTasks archives all pending tasks from the given queue,
   659  // and reports the number of tasks archived.
   660  func (i *Inspector) ArchiveAllPendingTasks(queue string) (int, error) {
   661  	if err := base.ValidateQueueName(queue); err != nil {
   662  		return 0, err
   663  	}
   664  	n, err := i.rdb.ArchiveAllPendingTasks(queue)
   665  	return int(n), err
   666  }
   667  
   668  // ArchiveAllScheduledTasks archives all scheduled tasks from the given queue,
   669  // and reports the number of tasks archiveed.
   670  func (i *Inspector) ArchiveAllScheduledTasks(queue string) (int, error) {
   671  	if err := base.ValidateQueueName(queue); err != nil {
   672  		return 0, err
   673  	}
   674  	n, err := i.rdb.ArchiveAllScheduledTasks(queue)
   675  	return int(n), err
   676  }
   677  
   678  // ArchiveAllRetryTasks archives all retry tasks from the given queue,
   679  // and reports the number of tasks archiveed.
   680  func (i *Inspector) ArchiveAllRetryTasks(queue string) (int, error) {
   681  	if err := base.ValidateQueueName(queue); err != nil {
   682  		return 0, err
   683  	}
   684  	n, err := i.rdb.ArchiveAllRetryTasks(queue)
   685  	return int(n), err
   686  }
   687  
   688  // ArchiveAllAggregatingTasks archives all tasks from the given group,
   689  // and reports the number of tasks archived.
   690  func (i *Inspector) ArchiveAllAggregatingTasks(queue, group string) (int, error) {
   691  	if err := base.ValidateQueueName(queue); err != nil {
   692  		return 0, err
   693  	}
   694  	n, err := i.rdb.ArchiveAllAggregatingTasks(queue, group)
   695  	return int(n), err
   696  }
   697  
   698  // ArchiveTask archives a task with the given id in the given queue.
   699  // The task needs to be in pending, scheduled, or retry state, otherwise ArchiveTask
   700  // will return an error.
   701  //
   702  // If a queue with the given name doesn't exist, it returns an error wrapping ErrQueueNotFound.
   703  // If a task with the given id doesn't exist in the queue, it returns an error wrapping ErrTaskNotFound.
   704  // If the task is in already archived, it returns a non-nil error.
   705  func (i *Inspector) ArchiveTask(queue, id string) error {
   706  	if err := base.ValidateQueueName(queue); err != nil {
   707  		return fmt.Errorf("asynq: err")
   708  	}
   709  	err := i.rdb.ArchiveTask(queue, id)
   710  	switch {
   711  	case errors.IsQueueNotFound(err):
   712  		return fmt.Errorf("asynq: %w", ErrQueueNotFound)
   713  	case errors.IsTaskNotFound(err):
   714  		return fmt.Errorf("asynq: %w", ErrTaskNotFound)
   715  	case err != nil:
   716  		return fmt.Errorf("asynq: %v", err)
   717  	}
   718  	return nil
   719  }
   720  
   721  // CancelProcessing sends a signal to cancel processing of the task
   722  // given a task id. CancelProcessing is best-effort, which means that it does not
   723  // guarantee that the task with the given id will be canceled. The return
   724  // value only indicates whether the cancelation signal has been sent.
   725  func (i *Inspector) CancelProcessing(id string) error {
   726  	return i.rdb.PublishCancelation(id)
   727  }
   728  
   729  // PauseQueue pauses task processing on the specified queue.
   730  // If the queue is already paused, it will return a non-nil error.
   731  func (i *Inspector) PauseQueue(queue string) error {
   732  	if err := base.ValidateQueueName(queue); err != nil {
   733  		return err
   734  	}
   735  	return i.rdb.Pause(queue)
   736  }
   737  
   738  // UnpauseQueue resumes task processing on the specified queue.
   739  // If the queue is not paused, it will return a non-nil error.
   740  func (i *Inspector) UnpauseQueue(queue string) error {
   741  	if err := base.ValidateQueueName(queue); err != nil {
   742  		return err
   743  	}
   744  	return i.rdb.Unpause(queue)
   745  }
   746  
   747  // Servers return a list of running servers' information.
   748  func (i *Inspector) Servers() ([]*ServerInfo, error) {
   749  	servers, err := i.rdb.ListServers()
   750  	if err != nil {
   751  		return nil, err
   752  	}
   753  	workers, err := i.rdb.ListWorkers()
   754  	if err != nil {
   755  		return nil, err
   756  	}
   757  	m := make(map[string]*ServerInfo) // ServerInfo keyed by serverID
   758  	for _, s := range servers {
   759  		m[s.ServerID] = &ServerInfo{
   760  			ID:             s.ServerID,
   761  			Host:           s.Host,
   762  			PID:            s.PID,
   763  			Concurrency:    s.Concurrency,
   764  			Queues:         s.Queues,
   765  			StrictPriority: s.StrictPriority,
   766  			Started:        s.Started,
   767  			Status:         s.Status,
   768  			ActiveWorkers:  make([]*WorkerInfo, 0),
   769  		}
   770  	}
   771  	for _, w := range workers {
   772  		srvInfo, ok := m[w.ServerID]
   773  		if !ok {
   774  			continue
   775  		}
   776  		wrkInfo := &WorkerInfo{
   777  			TaskID:      w.ID,
   778  			TaskType:    w.Type,
   779  			TaskPayload: w.Payload,
   780  			Queue:       w.Queue,
   781  			Started:     w.Started,
   782  			Deadline:    w.Deadline,
   783  		}
   784  		srvInfo.ActiveWorkers = append(srvInfo.ActiveWorkers, wrkInfo)
   785  	}
   786  	var out []*ServerInfo
   787  	for _, srvInfo := range m {
   788  		out = append(out, srvInfo)
   789  	}
   790  	return out, nil
   791  }
   792  
   793  // ServerInfo describes a running Server instance.
   794  type ServerInfo struct {
   795  	// Unique Identifier for the server.
   796  	ID string
   797  	// Host machine on which the server is running.
   798  	Host string
   799  	// PID of the process in which the server is running.
   800  	PID int
   801  
   802  	// Server configuration details.
   803  	// See Config doc for field descriptions.
   804  	Concurrency    int
   805  	Queues         map[string]int
   806  	StrictPriority bool
   807  
   808  	// Time the server started.
   809  	Started time.Time
   810  	// Status indicates the status of the server.
   811  	// TODO: Update comment with more details.
   812  	Status string
   813  	// A List of active workers currently processing tasks.
   814  	ActiveWorkers []*WorkerInfo
   815  }
   816  
   817  // WorkerInfo describes a running worker processing a task.
   818  type WorkerInfo struct {
   819  	// ID of the task the worker is processing.
   820  	TaskID string
   821  	// Type of the task the worker is processing.
   822  	TaskType string
   823  	// Payload of the task the worker is processing.
   824  	TaskPayload []byte
   825  	// Queue from which the worker got its task.
   826  	Queue string
   827  	// Time the worker started processing the task.
   828  	Started time.Time
   829  	// Time the worker needs to finish processing the task by.
   830  	Deadline time.Time
   831  }
   832  
   833  // ClusterKeySlot returns an integer identifying the hash slot the given queue hashes to.
   834  func (i *Inspector) ClusterKeySlot(queue string) (int64, error) {
   835  	return i.rdb.ClusterKeySlot(queue)
   836  }
   837  
   838  // ClusterNode describes a node in redis cluster.
   839  type ClusterNode struct {
   840  	// Node ID in the cluster.
   841  	ID string
   842  
   843  	// Address of the node.
   844  	Addr string
   845  }
   846  
   847  // ClusterNodes returns a list of nodes the given queue belongs to.
   848  //
   849  // Only relevant if task queues are stored in redis cluster.
   850  func (i *Inspector) ClusterNodes(queue string) ([]*ClusterNode, error) {
   851  	nodes, err := i.rdb.ClusterNodes(queue)
   852  	if err != nil {
   853  		return nil, err
   854  	}
   855  	var res []*ClusterNode
   856  	for _, node := range nodes {
   857  		res = append(res, &ClusterNode{ID: node.ID, Addr: node.Addr})
   858  	}
   859  	return res, nil
   860  }
   861  
   862  // SchedulerEntry holds information about a periodic task registered with a scheduler.
   863  type SchedulerEntry struct {
   864  	// Identifier of this entry.
   865  	ID string
   866  
   867  	// Spec describes the schedule of this entry.
   868  	Spec string
   869  
   870  	// Periodic Task registered for this entry.
   871  	Task *Task
   872  
   873  	// Opts is the options for the periodic task.
   874  	Opts []Option
   875  
   876  	// Next shows the next time the task will be enqueued.
   877  	Next time.Time
   878  
   879  	// Prev shows the last time the task was enqueued.
   880  	// Zero time if task was never enqueued.
   881  	Prev time.Time
   882  }
   883  
   884  // SchedulerEntries returns a list of all entries registered with
   885  // currently running schedulers.
   886  func (i *Inspector) SchedulerEntries() ([]*SchedulerEntry, error) {
   887  	var entries []*SchedulerEntry
   888  	res, err := i.rdb.ListSchedulerEntries()
   889  	if err != nil {
   890  		return nil, err
   891  	}
   892  	for _, e := range res {
   893  		task := NewTask(e.Type, e.Payload)
   894  		var opts []Option
   895  		for _, s := range e.Opts {
   896  			if o, err := parseOption(s); err == nil {
   897  				// ignore bad data
   898  				opts = append(opts, o)
   899  			}
   900  		}
   901  		entries = append(entries, &SchedulerEntry{
   902  			ID:   e.ID,
   903  			Spec: e.Spec,
   904  			Task: task,
   905  			Opts: opts,
   906  			Next: e.Next,
   907  			Prev: e.Prev,
   908  		})
   909  	}
   910  	return entries, nil
   911  }
   912  
   913  // parseOption interprets a string s as an Option and returns the Option if parsing is successful,
   914  // otherwise returns non-nil error.
   915  func parseOption(s string) (Option, error) {
   916  	fn, arg := parseOptionFunc(s), parseOptionArg(s)
   917  	switch fn {
   918  	case "Queue":
   919  		queue, err := strconv.Unquote(arg)
   920  		if err != nil {
   921  			return nil, err
   922  		}
   923  		return Queue(queue), nil
   924  	case "MaxRetry":
   925  		n, err := strconv.Atoi(arg)
   926  		if err != nil {
   927  			return nil, err
   928  		}
   929  		return MaxRetry(n), nil
   930  	case "Timeout":
   931  		d, err := time.ParseDuration(arg)
   932  		if err != nil {
   933  			return nil, err
   934  		}
   935  		return Timeout(d), nil
   936  	case "Deadline":
   937  		t, err := time.Parse(time.UnixDate, arg)
   938  		if err != nil {
   939  			return nil, err
   940  		}
   941  		return Deadline(t), nil
   942  	case "Unique":
   943  		d, err := time.ParseDuration(arg)
   944  		if err != nil {
   945  			return nil, err
   946  		}
   947  		return Unique(d), nil
   948  	case "ProcessAt":
   949  		t, err := time.Parse(time.UnixDate, arg)
   950  		if err != nil {
   951  			return nil, err
   952  		}
   953  		return ProcessAt(t), nil
   954  	case "ProcessIn":
   955  		d, err := time.ParseDuration(arg)
   956  		if err != nil {
   957  			return nil, err
   958  		}
   959  		return ProcessIn(d), nil
   960  	case "Retention":
   961  		d, err := time.ParseDuration(arg)
   962  		if err != nil {
   963  			return nil, err
   964  		}
   965  		return Retention(d), nil
   966  	default:
   967  		return nil, fmt.Errorf("cannot not parse option string %q", s)
   968  	}
   969  }
   970  
   971  func parseOptionFunc(s string) string {
   972  	i := strings.Index(s, "(")
   973  	return s[:i]
   974  }
   975  
   976  func parseOptionArg(s string) string {
   977  	i := strings.Index(s, "(")
   978  	if i >= 0 {
   979  		j := strings.Index(s, ")")
   980  		if j > i {
   981  			return s[i+1 : j]
   982  		}
   983  	}
   984  	return ""
   985  }
   986  
   987  // SchedulerEnqueueEvent holds information about an enqueue event by a scheduler.
   988  type SchedulerEnqueueEvent struct {
   989  	// ID of the task that was enqueued.
   990  	TaskID string
   991  
   992  	// Time the task was enqueued.
   993  	EnqueuedAt time.Time
   994  }
   995  
   996  // ListSchedulerEnqueueEvents retrieves a list of enqueue events from the specified scheduler entry.
   997  //
   998  // By default, it retrieves the first 30 tasks.
   999  func (i *Inspector) ListSchedulerEnqueueEvents(entryID string, opts ...ListOption) ([]*SchedulerEnqueueEvent, error) {
  1000  	opt := composeListOptions(opts...)
  1001  	pgn := rdb.Pagination{Size: opt.pageSize, Page: opt.pageNum - 1}
  1002  	data, err := i.rdb.ListSchedulerEnqueueEvents(entryID, pgn)
  1003  	if err != nil {
  1004  		return nil, err
  1005  	}
  1006  	var events []*SchedulerEnqueueEvent
  1007  	for _, e := range data {
  1008  		events = append(events, &SchedulerEnqueueEvent{TaskID: e.TaskID, EnqueuedAt: e.EnqueuedAt})
  1009  	}
  1010  	return events, nil
  1011  }