github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/README.md (about)

     1  <img src="https://user-images.githubusercontent.com/11155743/114697792-ffbfa580-9d26-11eb-8e5b-33bef69476dc.png" alt="Asynq logo" width="360px" />
     2  
     3  # Simple, reliable & efficient distributed task queue in Go
     4  
     5  [![GoDoc](https://godoc.org/github.com/hibiken/asynq?status.svg)](https://godoc.org/github.com/hibiken/asynq)
     6  [![Go Report Card](https://goreportcard.com/badge/github.com/hibiken/asynq)](https://goreportcard.com/report/github.com/hibiken/asynq)
     7  ![Build Status](https://github.com/hibiken/asynq/workflows/build/badge.svg)
     8  [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
     9  [![Gitter chat](https://badges.gitter.im/go-asynq/gitter.svg)](https://gitter.im/go-asynq/community)
    10  
    11  Asynq is a Go library for queueing tasks and processing them asynchronously with workers. It's backed by [Redis](https://redis.io/) and is designed to be scalable yet easy to get started.
    12  
    13  Highlevel overview of how Asynq works:
    14  
    15  - Client puts tasks on a queue
    16  - Server pulls tasks off queues and starts a worker goroutine for each task
    17  - Tasks are processed concurrently by multiple workers
    18  
    19  Task queues are used as a mechanism to distribute work across multiple machines. A system can consist of multiple worker servers and brokers, giving way to high availability and horizontal scaling.
    20  
    21  **Example use case**
    22  
    23  ![Task Queue Diagram](https://user-images.githubusercontent.com/11155743/116358505-656f5f80-a806-11eb-9c16-94e49dab0f99.jpg)
    24  
    25  ## Features
    26  
    27  - Guaranteed [at least one execution](https://www.cloudcomputingpatterns.org/at_least_once_delivery/) of a task
    28  - Scheduling of tasks
    29  - [Retries](https://github.com/hibiken/asynq/wiki/Task-Retry) of failed tasks
    30  - Automatic recovery of tasks in the event of a worker crash
    31  - [Weighted priority queues](https://github.com/hibiken/asynq/wiki/Queue-Priority#weighted-priority)
    32  - [Strict priority queues](https://github.com/hibiken/asynq/wiki/Queue-Priority#strict-priority)
    33  - Low latency to add a task since writes are fast in Redis
    34  - De-duplication of tasks using [unique option](https://github.com/hibiken/asynq/wiki/Unique-Tasks)
    35  - Allow [timeout and deadline per task](https://github.com/hibiken/asynq/wiki/Task-Timeout-and-Cancelation)
    36  - Allow [aggregating group of tasks](https://github.com/hibiken/asynq/wiki/Task-aggregation) to batch multiple successive operations
    37  - [Flexible handler interface with support for middlewares](https://github.com/hibiken/asynq/wiki/Handler-Deep-Dive)
    38  - [Ability to pause queue](/tools/asynq/README.md#pause) to stop processing tasks from the queue
    39  - [Periodic Tasks](https://github.com/hibiken/asynq/wiki/Periodic-Tasks)
    40  - [Support Redis Cluster](https://github.com/hibiken/asynq/wiki/Redis-Cluster) for automatic sharding and high availability
    41  - [Support Redis Sentinels](https://github.com/hibiken/asynq/wiki/Automatic-Failover) for high availability
    42  - Integration with [Prometheus](https://prometheus.io/) to collect and visualize queue metrics
    43  - [Web UI](#web-ui) to inspect and remote-control queues and tasks
    44  - [CLI](#command-line-tool) to inspect and remote-control queues and tasks
    45  
    46  ## Stability and Compatibility
    47  
    48  **Status**: The library is currently undergoing **heavy development** with frequent, breaking API changes.
    49  
    50  > ☝️ **Important Note**: Current major version is zero (`v0.x.x`) to accommodate rapid development and fast iteration while getting early feedback from users (_feedback on APIs are appreciated!_). The public API could change without a major version update before `v1.0.0` release.
    51  
    52  ## Sponsoring
    53  If you are using this package in production, **please consider sponsoring the project to show your support!**
    54  
    55  ## Quickstart
    56  
    57  Make sure you have Go installed ([download](https://golang.org/dl/)). Version `1.14` or higher is required.
    58  
    59  Initialize your project by creating a folder and then running `go mod init github.com/your/repo` ([learn more](https://blog.golang.org/using-go-modules)) inside the folder. Then install Asynq library with the [`go get`](https://golang.org/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) command:
    60  
    61  ```sh
    62  go get -u github.com/hibiken/asynq
    63  ```
    64  
    65  Make sure you're running a Redis server locally or from a [Docker](https://hub.docker.com/_/redis) container. Version `4.0` or higher is required.
    66  
    67  Next, write a package that encapsulates task creation and task handling.
    68  
    69  ```go
    70  package tasks
    71  
    72  import (
    73      "context"
    74      "encoding/json"
    75      "fmt"
    76      "log"
    77      "time"
    78      "github.com/hibiken/asynq"
    79  )
    80  
    81  // A list of task types.
    82  const (
    83      TypeEmailDelivery   = "email:deliver"
    84      TypeImageResize     = "image:resize"
    85  )
    86  
    87  type EmailDeliveryPayload struct {
    88      UserID     int
    89      TemplateID string
    90  }
    91  
    92  type ImageResizePayload struct {
    93      SourceURL string
    94  }
    95  
    96  //----------------------------------------------
    97  // Write a function NewXXXTask to create a task.
    98  // A task consists of a type and a payload.
    99  //----------------------------------------------
   100  
   101  func NewEmailDeliveryTask(userID int, tmplID string) (*asynq.Task, error) {
   102      payload, err := json.Marshal(EmailDeliveryPayload{UserID: userID, TemplateID: tmplID})
   103      if err != nil {
   104          return nil, err
   105      }
   106      return asynq.NewTask(TypeEmailDelivery, payload), nil
   107  }
   108  
   109  func NewImageResizeTask(src string) (*asynq.Task, error) {
   110      payload, err := json.Marshal(ImageResizePayload{SourceURL: src})
   111      if err != nil {
   112          return nil, err
   113      }
   114      // task options can be passed to NewTask, which can be overridden at enqueue time.
   115      return asynq.NewTask(TypeImageResize, payload, asynq.MaxRetry(5), asynq.Timeout(20 * time.Minute)), nil
   116  }
   117  
   118  //---------------------------------------------------------------
   119  // Write a function HandleXXXTask to handle the input task.
   120  // Note that it satisfies the asynq.HandlerFunc interface.
   121  //
   122  // Handler doesn't need to be a function. You can define a type
   123  // that satisfies asynq.Handler interface. See examples below.
   124  //---------------------------------------------------------------
   125  
   126  func HandleEmailDeliveryTask(ctx context.Context, t *asynq.Task) error {
   127      var p EmailDeliveryPayload
   128      if err := json.Unmarshal(t.Payload(), &p); err != nil {
   129          return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
   130      }
   131      log.Printf("Sending Email to User: user_id=%d, template_id=%s", p.UserID, p.TemplateID)
   132      // Email delivery code ...
   133      return nil
   134  }
   135  
   136  // ImageProcessor implements asynq.Handler interface.
   137  type ImageProcessor struct {
   138      // ... fields for struct
   139  }
   140  
   141  func (processor *ImageProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error {
   142      var p ImageResizePayload
   143      if err := json.Unmarshal(t.Payload(), &p); err != nil {
   144          return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry)
   145      }
   146      log.Printf("Resizing image: src=%s", p.SourceURL)
   147      // Image resizing code ...
   148      return nil
   149  }
   150  
   151  func NewImageProcessor() *ImageProcessor {
   152  	return &ImageProcessor{}
   153  }
   154  ```
   155  
   156  In your application code, import the above package and use [`Client`](https://pkg.go.dev/github.com/hibiken/asynq?tab=doc#Client) to put tasks on queues.
   157  
   158  ```go
   159  package main
   160  
   161  import (
   162      "log"
   163      "time"
   164  
   165      "github.com/hibiken/asynq"
   166      "your/app/package/tasks"
   167  )
   168  
   169  const redisAddr = "127.0.0.1:6379"
   170  
   171  func main() {
   172      client := asynq.NewClient(asynq.RedisClientOpt{Addr: redisAddr})
   173      defer client.Close()
   174  
   175      // ------------------------------------------------------
   176      // Example 1: Enqueue task to be processed immediately.
   177      //            Use (*Client).Enqueue method.
   178      // ------------------------------------------------------
   179  
   180      task, err := tasks.NewEmailDeliveryTask(42, "some:template:id")
   181      if err != nil {
   182          log.Fatalf("could not create task: %v", err)
   183      }
   184      info, err := client.Enqueue(task)
   185      if err != nil {
   186          log.Fatalf("could not enqueue task: %v", err)
   187      }
   188      log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
   189  
   190  
   191      // ------------------------------------------------------------
   192      // Example 2: Schedule task to be processed in the future.
   193      //            Use ProcessIn or ProcessAt option.
   194      // ------------------------------------------------------------
   195  
   196      info, err = client.Enqueue(task, asynq.ProcessIn(24*time.Hour))
   197      if err != nil {
   198          log.Fatalf("could not schedule task: %v", err)
   199      }
   200      log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
   201  
   202  
   203      // ----------------------------------------------------------------------------
   204      // Example 3: Set other options to tune task processing behavior.
   205      //            Options include MaxRetry, Queue, Timeout, Deadline, Unique etc.
   206      // ----------------------------------------------------------------------------
   207  
   208      task, err = tasks.NewImageResizeTask("https://example.com/myassets/image.jpg")
   209      if err != nil {
   210          log.Fatalf("could not create task: %v", err)
   211      }
   212      info, err = client.Enqueue(task, asynq.MaxRetry(10), asynq.Timeout(3 * time.Minute))
   213      if err != nil {
   214          log.Fatalf("could not enqueue task: %v", err)
   215      }
   216      log.Printf("enqueued task: id=%s queue=%s", info.ID, info.Queue)
   217  }
   218  ```
   219  
   220  Next, start a worker server to process these tasks in the background. To start the background workers, use [`Server`](https://pkg.go.dev/github.com/hibiken/asynq?tab=doc#Server) and provide your [`Handler`](https://pkg.go.dev/github.com/hibiken/asynq?tab=doc#Handler) to process the tasks.
   221  
   222  You can optionally use [`ServeMux`](https://pkg.go.dev/github.com/hibiken/asynq?tab=doc#ServeMux) to create a handler, just as you would with [`net/http`](https://golang.org/pkg/net/http/) Handler.
   223  
   224  ```go
   225  package main
   226  
   227  import (
   228      "log"
   229  
   230      "github.com/hibiken/asynq"
   231      "your/app/package/tasks"
   232  )
   233  
   234  const redisAddr = "127.0.0.1:6379"
   235  
   236  func main() {
   237      srv := asynq.NewServer(
   238          asynq.RedisClientOpt{Addr: redisAddr},
   239          asynq.Config{
   240              // Specify how many concurrent workers to use
   241              Concurrency: 10,
   242              // Optionally specify multiple queues with different priority.
   243              Queues: map[string]int{
   244                  "critical": 6,
   245                  "default":  3,
   246                  "low":      1,
   247              },
   248              // See the godoc for other configuration options
   249          },
   250      )
   251  
   252      // mux maps a type to a handler
   253      mux := asynq.NewServeMux()
   254      mux.HandleFunc(tasks.TypeEmailDelivery, tasks.HandleEmailDeliveryTask)
   255      mux.Handle(tasks.TypeImageResize, tasks.NewImageProcessor())
   256      // ...register other handlers...
   257  
   258      if err := srv.Run(mux); err != nil {
   259          log.Fatalf("could not run server: %v", err)
   260      }
   261  }
   262  ```
   263  
   264  For a more detailed walk-through of the library, see our [Getting Started](https://github.com/hibiken/asynq/wiki/Getting-Started) guide.
   265  
   266  To learn more about `asynq` features and APIs, see the package [godoc](https://godoc.org/github.com/hibiken/asynq).
   267  
   268  ## Web UI
   269  
   270  [Asynqmon](https://github.com/hibiken/asynqmon) is a web based tool for monitoring and administrating Asynq queues and tasks.
   271  
   272  Here's a few screenshots of the Web UI:
   273  
   274  **Queues view**
   275  
   276  ![Web UI Queues View](https://user-images.githubusercontent.com/11155743/114697016-07327f00-9d26-11eb-808c-0ac841dc888e.png)
   277  
   278  **Tasks view**
   279  
   280  ![Web UI TasksView](https://user-images.githubusercontent.com/11155743/114697070-1f0a0300-9d26-11eb-855c-d3ec263865b7.png)
   281  
   282  **Metrics view**
   283  <img width="1532" alt="Screen Shot 2021-12-19 at 4 37 19 PM" src="https://user-images.githubusercontent.com/10953044/146777420-cae6c476-bac6-469c-acce-b2f6584e8707.png">
   284  
   285  **Settings and adaptive dark mode**
   286  
   287  ![Web UI Settings and adaptive dark mode](https://user-images.githubusercontent.com/11155743/114697149-3517c380-9d26-11eb-9f7a-ae2dd00aad5b.png)
   288  
   289  For details on how to use the tool, refer to the tool's [README](https://github.com/hibiken/asynqmon#readme).
   290  
   291  ## Command Line Tool
   292  
   293  Asynq ships with a command line tool to inspect the state of queues and tasks.
   294  
   295  To install the CLI tool, run the following command:
   296  
   297  ```sh
   298  go install github.com/hibiken/asynq/tools/asynq
   299  ```
   300  
   301  Here's an example of running the `asynq dash` command:
   302  
   303  ![Gif](/docs/assets/dash.gif)
   304  
   305  For details on how to use the tool, refer to the tool's [README](/tools/asynq/README.md).
   306  
   307  ## Contributing
   308  
   309  We are open to, and grateful for, any contributions (GitHub issues/PRs, feedback on [Gitter channel](https://gitter.im/go-asynq/community), etc) made by the community.
   310  
   311  Please see the [Contribution Guide](/CONTRIBUTING.md) before contributing.
   312  
   313  ## License
   314  
   315  Copyright (c) 2019-present [Ken Hibino](https://github.com/hibiken) and [Contributors](https://github.com/hibiken/asynq/graphs/contributors). `Asynq` is free and open-source software licensed under the [MIT License](https://github.com/hibiken/asynq/blob/master/LICENSE). Official logo was created by [Vic Shóstak](https://github.com/koddr) and distributed under [Creative Commons](https://creativecommons.org/publicdomain/zero/1.0/) license (CC0 1.0 Universal).