简介

我们在 Web 开发中时常会遇到这样的需求,执行一个操作之后,需要给用户一定形式的通知。例如,用户下单之后通过邮件发送电子发票,网上购票支付后通过短信发送车次信息。但是这类需求并不需要非常及时,如果放在请求流程中处理,会影响请求的响应时间。这类任务我们一般使用异步的方式来执行。jobrunner就是其中一个用来执行异步任务的 Go 语言库。得益于强大的cron库,再搭配jobrunner的任务状态监控,jobrunner非常易于使用。

快速使用

本文使用 Go Modules。

创建目录并初始化:

  1. $ mkdir jobrunner && cd jobrunner
  2. $ go mod init github.com/go-quiz/go-daily-lib/jobrunner

安装jobrunner

  1. $ go get -u github.com/bamzi/jobrunner

使用:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/bamzi/jobrunner"
  6. )
  7. type GreetingJob struct {
  8. Name string
  9. }
  10. func (g GreetingJob) Run() {
  11. fmt.Println("Hello, ", g.Name)
  12. }
  13. func main() {
  14. jobrunner.Start()
  15. jobrunner.Schedule("@every 5s", GreetingJob{Name: "dj"})
  16. time.Sleep(10 * time.Second)
  17. }

我们创建一个任务,每隔 5s 打印一条欢迎信息。任务的创建和执行与cron完全相同,详细使用见我前面的一篇博文

注意,jobrunner需要先Start(),然后再添加任务。因为在Start()中创建MainCron对象,先添加任务会panic!!!

注意main函数尾的time.Sleep(10 * time.Second),因为主 goroutine 结束之后整个程序就退出了,jobrunner中的任务就没有机会被执行了。加上time.Sleep是为了让大家能看到输出,实际使用中不会这样做。

与 web 框架整合

jobrunner能很方便地与当前常见的 Web 框架整合,如Gin/Echo/Martini/Beego/Revel等。下面通过一个简单的例子演示如何在 Gin 中使用jobrunner:用户登录时给他的邮箱发送一封邮件。

首先需要安装相应的库:

  1. $ go get -u github.com/gin-gonic/gin
  2. $ github.com/jordan-wright/email

编写代码:

  1. package main
  2. import (
  3. "fmt"
  4. "net/smtp"
  5. "time"
  6. "github.com/bamzi/jobrunner"
  7. "github.com/gin-gonic/gin"
  8. "github.com/jordan-wright/email"
  9. )
  10. type EmailJob struct {
  11. Name string
  12. Email string
  13. }
  14. type User struct {
  15. Name string `form:"name"`
  16. Email string `form:"email"`
  17. }
  18. func (j EmailJob) Run() {
  19. e := email.NewEmail()
  20. e.From = "leego-quiz@126.com"
  21. e.To = []string{j.Email}
  22. e.Cc = []string{"leego-quiz@126.com"}
  23. e.Subject = "Welcome To Awesome-Web"
  24. e.Text = []byte(fmt.Sprintf(`
  25. Hello, %s
  26. Welcome Back
  27. `, j.Name))
  28. err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "leego-quiz@126.com", "yyyyyy", "smtp.126.com"))
  29. if err != nil {
  30. fmt.Printf("failed to send email to %s, err:%v", j.Name, err)
  31. }
  32. }
  33. func login(c *gin.Context) {
  34. var u User
  35. if c.ShouldBind(&u) == nil {
  36. c.String(200, "login success")
  37. jobrunner.In(5*time.Second, EmailJob{Name: u.Name, Email: u.Email})
  38. } else {
  39. c.String(404, "login failed")
  40. }
  41. }
  42. func main() {
  43. r := gin.Default()
  44. r.GET("/login", login)
  45. r.Run(":8888")
  46. }

这里只是为了简单演示,我们编写了一个简陋的login函数处理登录,传入nameemail,然后给该email发送邮件。email库的详细使用可以查看我之前的博文了解。

只需要在浏览器中输入http://localhost:8888/login?name=dj&email=935653229@qq.com,我的 QQ 邮箱就能收到邮件:

每日一库之50:jobrunner - 图1

监控

jobrunner内置了一个监控模块,可以很方便地通过网页或者 API 获取当前的任务状态数据:

  1. package main
  2. import (
  3. "fmt"
  4. "html/template"
  5. "os"
  6. "time"
  7. "github.com/bamzi/jobrunner"
  8. "github.com/gin-gonic/gin"
  9. )
  10. type GreetingJob struct {
  11. Name string
  12. }
  13. func (g GreetingJob) Run() {
  14. fmt.Println("Hello,", g.Name)
  15. }
  16. type EmailJob struct {
  17. Email string
  18. }
  19. func (e EmailJob) Run() {
  20. fmt.Println("Send,", e.Email)
  21. }
  22. func main() {
  23. r := gin.Default()
  24. jobrunner.Start()
  25. jobrunner.Every(5*time.Second, GreetingJob{Name: "dj"})
  26. jobrunner.Every(10*time.Second, EmailJob{Email: "935653229@qq.com"})
  27. r.GET("/jobrunner/json", JobJson)
  28. r.GET("/jobrunner/html", JobHtml)
  29. r.Run(":8888")
  30. }
  31. func JobJson(c *gin.Context) {
  32. c.JSON(200, jobrunner.StatusJson())
  33. }
  34. func JobHtml(c *gin.Context) {
  35. t, err := template.ParseFiles(os.Getenv("GOPATH") + "/src/github.com/bamzi/jobrunner/views/Status.html")
  36. if err != nil {
  37. c.JSON(400, "error")
  38. }
  39. t.Execute(c.Writer, jobrunner.StatusPage())
  40. }

运行之后,在浏览器中输入http://localhost:8888/jobrunner/html查看任务状态:

每日一库之50:jobrunner - 图2

这里显示任务名、任务 ID、状态、上次运行时间、下次运行时间以及处理延迟。

我们还可以通过http://localhost:8888/jobrunner/json获取原始 JSON 格式的数据自己处理:

每日一库之50:jobrunner - 图3

总结

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄

参考

  1. jobrunner GitHub:https://github.com/bamzi/jobrunner
  2. Go 每日一库 GitHub:https://github.com/go-quiz/go-daily-lib