場景
爬蟲業務場景,我們需要呼叫三方介面獲取代理ip地址,每個ip地址可以使用的時間有限和價格的,本著不浪費資源,我們在這裡做一層封裝。
當有其他業務呼叫我們介面的時候,會拉起定時任務,這個定時任務的生命週期為5分鐘,超過5分鐘這個定時任務就會停止,每一次請求時都會更新定時生命週期。這樣既保證其他業務呼叫時能及時拿到代理ip地址,空閒時間又不浪費資源。
程式碼實現
package main
import (
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
"net/http"
"sync"
"time"
)
type TaskManager struct {
cron *cron.Cron
entryID cron.EntryID
running bool
lifecycle int
lifecycleMux sync.Mutex
lifecycleTick *time.Ticker
stopChan chan struct{}
}
func NewTaskManager() *TaskManager {
return &TaskManager{
cron: cron.New(cron.WithSeconds()),
running: false,
stopChan: make(chan struct{}),
}
}
func (tm *TaskManager) StartTask() {
tm.lifecycleMux.Lock()
defer tm.lifecycleMux.Unlock()
if tm.running {
tm.lifecycle = 5
return
}
// 啟動定時任務,每分鐘執行一次
tm.entryID, _ = tm.cron.AddFunc("@every 1m", tm.task)
tm.cron.Start()
tm.running = true
tm.lifecycle = 5
// 啟動生命週期ticker,每分鐘遞減一次
tm.lifecycleTick = time.NewTicker(1 * time.Minute)
go tm.lifecycleManager()
}
func (tm *TaskManager) StopTask() {
tm.lifecycleMux.Lock()
defer tm.lifecycleMux.Unlock()
if tm.running {
tm.cron.Remove(tm.entryID)
tm.lifecycleTick.Stop()
close(tm.stopChan)
tm.running = false
println("Task has stopped")
}
}
func (tm *TaskManager) lifecycleManager() {
for {
select {
case <-tm.lifecycleTick.C:
tm.updateLifecycle()
case <-tm.stopChan:
return
}
}
}
func (tm *TaskManager) updateLifecycle() {
tm.lifecycleMux.Lock()
defer tm.lifecycleMux.Unlock()
tm.lifecycle--
if tm.lifecycle <= 0 {
tm.StopTask()
}
}
func (tm *TaskManager) task() {
// 這裡編寫定時任務要執行的邏輯
println("Task is running")
}
var taskManager = NewTaskManager()
func main() {
r := gin.Default()
// 定義請求處理函式
r.GET("/v1/ip", handleRequest)
r.Run(":8080")
}
func handleRequest(c *gin.Context) {
taskManager.StartTask()
c.JSON(http.StatusOK, gin.H{
"message": "Task lifecycle updated",
})
}
注意: 獲取的ip地址放到redis裡設定過期時間。程式碼只共參考大體邏輯,具體實現需要修改。