Asynq[1]是一个Go实现的分布式任务队列和异步处理库,基于redis,类似Ruby的sidekiq[2]和Python的celery[3]。Go生态类似的还有machinery[4]和goworker

同时提供一个WebUI asynqmon[5],可以源码形式安装或使用Docker image, 还可以和Prometheus集成

docker run --rm --name asynqmon -p 8080:8080 hibiken/asynqmon,如果使用的是主机上的redis,还需加上 --redis-addr=host.docker.internal:6379,否则会报错[6]

即 docker run --rm --name asynqmon -p 8080:8080 hibiken/asynqmon --redis-addr=host.docker.internal:6379

➜  asynq-demo git:(main) ✗ tree
.
├── client.go
├── const.go
├── go.mod
├── go.sum
└── server.go

0 directories, 5 files

其中const.go:

package main

const (
 redisAddr   = "127.0.0.1:6379"
 redisPasswd = ""
)

const (
 TypeExampleTask    = "shuang:asynq-task:example"
)

client.go:


package main

import (
 "encoding/json"
 "fmt"
 "log"
 "time"

 "github.com/hibiken/asynq"
)

type ExampleTaskPayload struct {
 UserID string
 Msg    string
 // 业务需要的其他字段
}

func NewExampleTask(userID string, msg string) (*asynq.Task, error) {
 payload, err := json.Marshal(ExampleTaskPayload{UserID: userID, Msg: msg})
 if err != nil {
  return nil, err
 }
 return asynq.NewTask(TypeExampleTask, payload), nil
}

var client *asynq.Client

func main() {

 client = asynq.NewClient(asynq.RedisClientOpt{Addr: redisAddr, Password: redisPasswd, DB: 0})
 defer client.Close()

 //go startExampleTask()
 startExampleTask()

 //startGithubUpdate() // 定时触发
}

func startExampleTask() {

 fmt.Println("开始执行一次性的任务")
 // 立刻执行
 task1, err := NewExampleTask("10001", "mashangzhixing!")
 if err != nil {
  log.Fatalf("could not create task: %v", err)
 }

 info, err := client.Enqueue(task1)
 if err != nil {
  log.Fatalf("could not enqueue task: %v", err)
 }
 log.Printf("task1 -> enqueued task: id=%s queue=%s", info.ID, info.Queue)

 // 10秒后执行(定时执行)
 task2, err := NewExampleTask("10002", "10s houzhixing")
 if err != nil {
  log.Fatalf("could not create task: %v", err)
 }

 info, err = client.Enqueue(task2, asynq.ProcessIn(10*time.Second))
 if err != nil {
  log.Fatalf("could not enqueue task: %v", err)
 }
 log.Printf("task2 -> enqueued task: id=%s queue=%s", info.ID, info.Queue)

 // 30s后执行(定时执行)
 task3, err := NewExampleTask("10003", "30s houzhixing")
 if err != nil {
  log.Fatalf("could not create task: %v", err)
 }

 theTime := time.Now().Add(30 * time.Second)
 info, err = client.Enqueue(task3, asynq.ProcessAt(theTime))
 if err != nil {
  log.Fatalf("could not enqueue task: %v", err)
 }
 log.Printf("task3 -> enqueued task: id=%s queue=%s", info.ID, info.Queue)
}

server.go:

package main

import (
 "context"
 "encoding/json"
 "fmt"
 "time"

 "github.com/davecgh/go-spew/spew"
 "github.com/hibiken/asynq"
)

var AsynqServer *asynq.Server // 异步任务server

func initTaskServer() error {
 // 初始化异步任务服务端
 AsynqServer = asynq.NewServer(
  asynq.RedisClientOpt{
   Addr:     redisAddr,
   Password: redisPasswd, //与client对应
   DB:       0,
  },
  asynq.Config{
   // Specify how many concurrent workers to use
   Concurrency: 100,
   // Optionally specify multiple queues with different priority.
   Queues: map[string]int{
    "critical": 6,
    "default":  3,
    "low":      1,
   },
   // See the godoc for other configuration options
  },
 )
 return nil
}

func main() {
 initTaskServer()
 mux := asynq.NewServeMux()

 mux.HandleFunc(TypeExampleTask, HandleExampleTask)
 // ...register other handlers...

 if err := AsynqServer.Run(mux); err != nil {
  fmt.Printf("could not run asynq server: %v", err)
 }
}

func HandleExampleTask(ctx context.Context, t *asynq.Task) error {

 res := make(map[string]string)

 spew.Dump("t.Payload() is:", t.Payload())
 err := json.Unmarshal(t.Payload(), &res)
 if err != nil {
  fmt.Printf("rum session, can not parse payload: %s,  err: %v", t.Payload(), err)
  return nil
 }
 //-----------具体处理逻辑------------
 spew.Println("拿到的入参为:", res, "接下来将进行具体处理")
 fmt.Println()
 // 模拟具体的处理
 time.Sleep(5 * time.Second)
 fmt.Println("--------------处理了5s,处理完成-----------------")

 return nil

}

执行redis-server

清除redis中所有的key:

执行docker run --rm --name asynqmon -p 8080:8080 hibiken/asynqmon --redis-addr=host.docker.internal:6379

执行 go run client.go const.go (生产者,产生消息放入队列)

此时能看到redis中多个几个key

同时管理后台能看到队列的信息

执行 go run server.go const.go (消费者,消费队列中的消息)

可以看到都被处理了

此时redis中的key:

此处的业务处理为模拟,实际可能是某个被触发后不需要马上执行的操作

相关文档:

golang之异步队列Asynq的更多相关文章

  1. .Net中的并行编程-4.实现高性能异步队列

    上文<.Net中的并行编程-3.ConcurrentQueue实现与分析>分析了ConcurrentQueue的实现,本章就基于ConcurrentQueue实现一个高性能的异步队列,该队 ...

  2. jquery ajax 对异步队列defer与XMLHttprequest.onload的依赖

    ajax 对异步队列defer与XMLHttprequest.onload的依赖

  3. 异步队列 Deferred

    异步队列 Deferred 背景: 移动web app开发,异步代码是时常的事,比如有常见的异步操作: Ajax(XMLHttpRequest) Image Tag,Script Tag,iframe ...

  4. [js高手之路]javascript腾讯面试题学习封装一个简易的异步队列

    这道js的面试题,是这样的,页面上有一个按钮,一个ul,点击按钮的时候,每隔1秒钟向ul的后面追加一个li, 一共追加10个,li的内容从0开始技术( 0, 1, 2, ....9 ),首先我们用闭包 ...

  5. .Net中的并行编程-7.基于BlockingCollection实现高性能异步队列

    三年前写过基于ConcurrentQueue的异步队列,今天在整理代码的时候发现当时另外一种实现方式-使用BlockingCollection实现,这种方式目前依然在实际项目中使用.关于Blockin ...

  6. 基于异步队列的生产者消费者C#并发设计

    继上文<<基于阻塞队列的生产者消费者C#并发设计>>的并发队列版本的并发设计,原文code是基于<<.Net中的并行编程-4.实现高性能异步队列>>修改 ...

  7. js异步队列之理解

    起因 最近看到一篇关于js异步执行顺序的解答,觉得有所收获,遂记录下来. marcotask和microtask js中异步队列可以分为两类,marcotask队列和microtask队列, marc ...

  8. jQuery源码分析(九) 异步队列模块 Deferred 详解

    deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等.(P.s:紧跟上一节:https://www.cnblogs.com/grea ...

  9. jQuery 源码解析(八) 异步队列模块 Callbacks 回调函数详解

    异步队列用于实现异步任务和回调函数的解耦,为ajax模块.队列模块.ready事件提供基础功能,包含三个部分:Query.Callbacks(flags).jQuery.Deferred(funct) ...

  10. Laravel异步队列全攻略

    最近项目需求,研究了laravel的异步队列.官方文档虽然很是详细,但也有些晦涩难懂,在此记录下步骤,供大家参考. 1.修改/config/queue.php文件 <?php return [ ...

随机推荐

  1. C# – 冷知识 (新手)

    替 Action/Func Parameter 设置名字 public static void MatchBracket(string value, string bracket, Action< ...

  2. .NET 的 Native AOT 现在是什么样的?

    今天要写的这篇文章源自昨天在朋友圈发的文章<UWP 通过 .NET 9 和Native AOT 的支持实现 UWP 应用的现代化>[1],一位小伙伴的对话让我想全面梳理下Native AO ...

  3. 报名开启|和你约定在 "Google 应用出海指南针"

    Google 谷歌发布的<2021 移动应用全球化指南>报告中提到,在移动互联网高度渗透的当下,全球用户迸发出来的广泛需求为中国新生代创业者带来了巨大的历史机遇.过去十年,依托于技术和人才 ...

  4. ConcurrentLinkedQueue详解(图文并茂)

    前言 ConcurrentLinkedQueue是基于链接节点的无界线程安全队列.此队列按照FIFO(先进先出)原则对元素进行排序.队列的头部是队列中存在时间最长的元素,而队列的尾部则是最近添加的元素 ...

  5. laravel框架接口

    下面是增删改查的接口,在使用过程中按自己需求对代码进行更改 控制器代码 <?php namespace App\Http\Controllers; use App\Models\Fang; us ...

  6. Nuxt.js 应用中的 app:rendered 钩子详解

    title: Nuxt.js 应用中的 app:rendered 钩子详解 date: 2024/10/2 updated: 2024/10/2 author: cmdragon excerpt: 摘 ...

  7. 可视化U-Net编码器每层的输出(在已经训练好的模型下展示,并不是初始训练阶段展示)

    想看一下对于一个训练好的模型,其每一层编码阶段的可视化输出是什么样子的.我以3Dircabd肝脏血管分割为例,训练好了一个U-Net模型.然后使用该模型在推理阶段使用,并可视化了每一层编码器. 分割结 ...

  8. 数据库运维实操优质文章分享(含Oracle、MySQL等) | 2024年7月刊

    本文为大家整理了墨天轮数据社区2024年7月发布的优质技术文章/文档,主题涵盖Oracle.MySQL.PostgreSQL等主流数据库系统以及国产数据库的深度教程和实用指南.从基础的安装配置到复杂的 ...

  9. kotlin类与对象——>可见性修饰符

    1.在 Kotlin 中有这四个可⻅性修饰符:private .protected .internal 和public .如果没有显式指定修饰符的话,默认可⻅性是 public . 2.包,函数.属性 ...

  10. 修复 KubeSphere 内置 Jenkins 的 Apache Log4j2 漏洞

    作者:老Z,中电信数智科技有限公司山东分公司运维架构师,云原生爱好者,目前专注于云原生运维,云原生领域技术栈涉及 Kubernetes.KubeSphere.DevOps.OpenStack.Ansi ...