golang 接口按需获取资源
场景
爬虫业务场景,我们需要调用三方接口获取代理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里设置过期时间。代码只共参考大体逻辑,具体实现需要修改。