Go 每日一庫之 jobrunner
簡(jiǎn)介
我們?cè)?Web 開發(fā)中時(shí)常會(huì)遇到這樣的需求,執(zhí)行一個(gè)操作之后,需要給用戶一定形式的通知。例如,用戶下單之后通過郵件發(fā)送電子發(fā)票,網(wǎng)上購票支付后通過短信發(fā)送車次信息。但是這類需求并不需要非常及時(shí),如果放在請(qǐng)求流程中處理,會(huì)影響請(qǐng)求的響應(yīng)時(shí)間。這類任務(wù)我們一般使用異步的方式來執(zhí)行。jobrunner就是其中一個(gè)用來執(zhí)行異步任務(wù)的 Go 語言庫。得益于強(qiáng)大的cron庫,再搭配jobrunner的任務(wù)狀態(tài)監(jiān)控,jobrunner非常易于使用。
快速使用
本文使用 Go Modules。
創(chuàng)建目錄并初始化:
$ mkdir jobrunner && cd jobrunner
$ go mod init github.com/darjun/go-daily-lib/jobrunner
安裝jobrunner:
$ go get -u github.com/bamzi/jobrunner
使用:
package?main
import?(
??"fmt"
??"time"
??"github.com/bamzi/jobrunner"
)
type?GreetingJob?struct?{
??Name?string
}
func?(g?GreetingJob)?Run()?{
??fmt.Println("Hello,?",?g.Name)
}
func?main()?{
??jobrunner.Start()
??jobrunner.Schedule("@every?5s",?GreetingJob{Name:?"dj"})
??time.Sleep(10?*?time.Second)
}
我們創(chuàng)建一個(gè)任務(wù),每隔 5s 打印一條歡迎信息。任務(wù)的創(chuàng)建和執(zhí)行與cron完全相同,詳細(xì)使用見我前面的一篇博文。
注意,jobrunner需要先Start(),然后再添加任務(wù)。因?yàn)樵?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Start()中創(chuàng)建MainCron對(duì)象,先添加任務(wù)會(huì)panic!!!
注意main函數(shù)尾的time.Sleep(10 * time.Second),因?yàn)橹?goroutine 結(jié)束之后整個(gè)程序就退出了,jobrunner中的任務(wù)就沒有機(jī)會(huì)被執(zhí)行了。加上time.Sleep是為了讓大家能看到輸出,實(shí)際使用中不會(huì)這樣做。
與 web 框架整合
jobrunner能很方便地與當(dāng)前常見的 Web 框架整合,如Gin/Echo/Martini/Beego/Revel等。下面通過一個(gè)簡(jiǎn)單的例子演示如何在 Gin 中使用jobrunner:用戶登錄時(shí)給他的郵箱發(fā)送一封郵件。
首先需要安裝相應(yīng)的庫:
$ go get -u github.com/gin-gonic/gin
$ github.com/jordan-wright/email
編寫代碼:
package?main
import?(
??"fmt"
??"net/smtp"
??"time"
??"github.com/bamzi/jobrunner"
??"github.com/gin-gonic/gin"
??"github.com/jordan-wright/email"
)
type?EmailJob?struct?{
??Name??string
??Email?string
}
type?User?struct?{
??Name??string?`form:"name"`
??Email?string?`form:"email"`
}
func?(j?EmailJob)?Run()?{
??e?:=?email.NewEmail()
??e.From?=?"[email protected]"
??e.To?=?[]string{j.Email}
??e.Cc?=?[]string{"[email protected]"}
??e.Subject?=?"Welcome?To?Awesome-Web"
??e.Text?=?[]byte(fmt.Sprintf(`
??Hello,?%s
??Welcome?Back
??`,?j.Name))
??err?:=?e.Send("smtp.126.com:25",?smtp.PlainAuth("",?"[email protected]",?"yyyyyy",?"smtp.126.com"))
??if?err?!=?nil?{
????fmt.Printf("failed?to?send?email?to?%s,?err:%v",?j.Name,?err)
??}
}
func?login(c?*gin.Context)?{
??var?u?User
??if?c.ShouldBind(&u)?==?nil?{
????c.String(200,?"login?success")
????jobrunner.In(5*time.Second,?EmailJob{Name:?u.Name,?Email:?u.Email})
??}?else?{
????c.String(404,?"login?failed")
??}
}
func?main()?{
??r?:=?gin.Default()
??r.GET("/login",?login)
??r.Run(":8888")
}
這里只是為了簡(jiǎn)單演示,我們編寫了一個(gè)簡(jiǎn)陋的login函數(shù)處理登錄,傳入name和email,然后給該email發(fā)送郵件。email庫的詳細(xì)使用可以查看我之前的博文了解。
只需要在瀏覽器中輸入http://localhost:8888/[email protected],我的 QQ 郵箱就能收到郵件:

監(jiān)控
jobrunner內(nèi)置了一個(gè)監(jiān)控模塊,可以很方便地通過網(wǎng)頁或者 API 獲取當(dāng)前的任務(wù)狀態(tài)數(shù)據(jù):
package?main
import?(
??"fmt"
??"html/template"
??"os"
??"time"
??"github.com/bamzi/jobrunner"
??"github.com/gin-gonic/gin"
)
type?GreetingJob?struct?{
??Name?string
}
func?(g?GreetingJob)?Run()?{
??fmt.Println("Hello,",?g.Name)
}
type?EmailJob?struct?{
??Email?string
}
func?(e?EmailJob)?Run()?{
??fmt.Println("Send,",?e.Email)
}
func?main()?{
??r?:=?gin.Default()
??jobrunner.Start()
??jobrunner.Every(5*time.Second,?GreetingJob{Name:?"dj"})
??jobrunner.Every(10*time.Second,?EmailJob{Email:?"[email protected]"})
??r.GET("/jobrunner/json",?JobJson)
??r.GET("/jobrunner/html",?JobHtml)
??r.Run(":8888")
}
func?JobJson(c?*gin.Context)?{
??c.JSON(200,?jobrunner.StatusJson())
}
func?JobHtml(c?*gin.Context)?{
??t,?err?:=?template.ParseFiles(os.Getenv("GOPATH")?+?"/src/github.com/bamzi/jobrunner/views/Status.html")
??if?err?!=?nil?{
????c.JSON(400,?"error")
??}
??t.Execute(c.Writer,?jobrunner.StatusPage())
}
運(yùn)行之后,在瀏覽器中輸入http://localhost:8888/jobrunner/html查看任務(wù)狀態(tài):

這里顯示任務(wù)名、任務(wù) ID、狀態(tài)、上次運(yùn)行時(shí)間、下次運(yùn)行時(shí)間以及處理延遲。
我們還可以通過http://localhost:8888/jobrunner/json獲取原始 JSON 格式的數(shù)據(jù)自己處理:

總結(jié)
大家如果發(fā)現(xiàn)好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue?
參考
jobrunner GitHub:https://github.com/bamzi/jobrunner Go 每日一庫 GitHub:https://github.com/darjun/go-daily-lib
推薦閱讀
站長(zhǎng) polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)
Go語言中文網(wǎng)
每天為你
分享 Go 知識(shí)
Go愛好者值得關(guān)注
