go延时队列
package main
import (
"errors"
"flag"
"fmt"
log "github.com/cihub/seelog"
"github.com/garyburd/redigo/redis"
"github.com/robfig/cron"
"runtime"
"strings"
"sync"
"time"
)
var ch chan int = make(chan int)
//声明一些全局变量
var (
pool *redis.Pool
redisServer = flag.String("h", "10.100.68.50:6379", "")
// redisServer = flag.String("h", "pre-mds-sa.bhptzj.0001.sae1.cache.amazonaws.com:6379", "")
redisPassword = flag.String("p", "", "")
redisDbName = flag.String("db", "1", "")
)
/**
* [timerLog description]
* @param {[type]} logFileName string [description]
* @param {[type]} logLevel string [Warning Debug Error Info]
* @param {[type]} logContent string [description]
* @return {[type]} [description]
*/
func timerLog(logLevel string, logContent string) {
config := `
<seelog>
<outputs formatid="testSeeLog">
<filter levels="debug,error,info">
<file path="./error.log" />
</filter>
</outputs>
<formats>
<format id="testSeeLog" format="%Date/%Time [%LEV] %Msg%n"/>
</formats>
</seelog>
`
defer log.Flush()
logger, _ := log.LoggerFromConfigAsBytes([]byte(config))
log.ReplaceLogger(logger)
if logLevel == "error" {
log.Error(logContent)
} else if logLevel == "debug" {
log.Error(logContent)
} else {
log.Info(logContent)
}
}
/**
* 初始化一个pool
*/
func newPool(server, password string) *redis.Pool {
return &redis.Pool{
MaxIdle: 3,
MaxActive: 5,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", server)
if err != nil {
fmt.Println("conn error:%s",err.Error())
timerLog("error", server+" conn error :"+err.Error())
return nil, err
}
if password != "" {
if _, err := c.Do("AUTH", password); err != nil {
c.Close()
fmt.Println("pass auth error :%s",err.Error())
timerLog("error", server+" pass auth error :"+err.Error())
return nil, err
}
}
if _, err := c.Do("SELECT", *redisDbName); err != nil {
fmt.Println("db exists error :%s",err.Error())
timerLog("error", server+" db exists error :"+err.Error())
c.Close()
return nil, err
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
if time.Since(t) < time.Minute {
return nil
}
_, err := c.Do("PING")
return err
},
}
}
var ErrValueFormatError = errors.New("bucket: value format is error,may be topic,id")
var ErrValueTypeError = errors.New("bucket: value type is error,may be number")
var lock sync.Mutex
func timerProcess(key string) (string, error) {
lock.Lock()
pool = newPool(*redisServer, *redisPassword)
conn := pool.Get()
defer func() {
pool.Close()
conn.Close()
lock.Unlock()
}()
// conn.Do("select",*redisDbName)
t := time.Now().Unix()
rs, errGet := redis.Values(conn.Do("ZREVRANGEBYSCORE", key, t, 0))
if errGet != nil {
timerLog("error", key+":"+errGet.Error())
return key, errGet
}
for _, v := range rs {
value := string(v.([]byte))
topicAndId := strings.Split(value, ",")
var topic string
var queueId string
if len(topicAndId) == 2 {
topic = topicAndId[0]
queueId = topicAndId[1]
_, errSet := conn.Do("rpush", topic, queueId)
if errSet != nil {
timerLog("error", key+"-"+value+":"+errSet.Error())
} else {
_, errDel := conn.Do("zrem", key, value)
if errDel != nil {
timerLog("error", key+"-"+value+":"+errDel.Error())
}
}
} else {
timerLog("error", key+"-"+value+":"+ErrValueFormatError.Error())
}
}
ch <- 1
return "success", nil
}
var dbLock sync.Mutex
func main() {
flag.Parse()
// fmt.Println("begin")
runtime.GOMAXPROCS(runtime.NumCPU())
/**
Seconds | Yes | 0-59 | * / , -
Minutes | Yes | 0-59 | * / , -
Hours | Yes | 0-23 | * / , -
Day of month | Yes | 1-31 | * / , - ?
Month | Yes | 1-12 or JAN-DEC | * / , -
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?
**/
c := cron.New()
spec := "*/1 * * * * *"
c.AddFunc(spec, func() {
dbLock.Lock()
pool = newPool(*redisServer, *redisPassword)
conn := pool.Get()
defer func() {
pool.Close()
conn.Close()
dbLock.Unlock()
}()
// conn.Do("SELECT",*redisDbName)
keys, errGet := redis.Values(conn.Do("keys", "DELAY_BUCKET_*"))
// fmt.Print(keys)
if errGet != nil {
timerLog("error", "get keys error:"+errGet.Error())
panic("get keys error:" + errGet.Error())
c.Stop()
}
for _, k := range keys {
key := string(k.([]byte))
// fmt.Println(key)
go timerProcess(key)
}
for i := 0; i < len(keys); i++ {
fmt.Println(i)
<-ch
}
})
c.Start()
select {}
}
go延时队列的更多相关文章
- 10 DelayQueue 延时队列类——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 www.cnblogs.com/oloroso/ 本文由乌合 ...
- 9 DelayQueueEntry 延时队列节点类——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
- 8 延时队列相关类——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
- 简析LIVE555中的延时队列
http://www.cnblogs.com/nightwatcher/archive/2011/04/10/2011158.html 最近在看LIVE555的源码,感觉其中的延时队列写的不错,于是就 ...
- Redis学习笔记之延时队列
目录 一.业务场景 二.Redis延时队列 一.业务场景 所谓延时队列就是延时的消息队列,下面说一下一些业务场景比较好理解 1.1 实践场景 订单支付失败,每隔一段时间提醒用户 用户并发量的情况,可以 ...
- 了解一下Redis队列【缓兵之计-延时队列】
https://www.cnblogs.com/wt645631686/p/8454021.html 我们平时习惯于使用 Rabbitmq 和 Kafka 作为消息队列中间件,来给应用程序之间增加 异 ...
- Redis简单延时队列
Redis实现简单延队列, 利用zset有序的数据结构, score设置为延时的时间戳. 实现思路: 1.使用命令 [zrangebyscore keyName socreMin socreMax] ...
- RabbitMQ学习之延时队列
原帖参考:http://www.cnblogs.com/telwanggs/p/7124687.html?utm_source=itdadao&utm_medium=referral http ...
- RabbitMQ进阶使用-延时队列的配置(Spring Boot)
依赖 MAVEN配置pom.xml <dependency> <groupId>org.springframework.boot</groupId> <art ...
- java实现rabbitMQ延时队列详解以及spring-rabbit整合教程
在实际的业务中我们会遇见生产者产生的消息,不立即消费,而是延时一段时间在消费.RabbitMQ本身没有直接支持延迟队列功能,但是我们可以根据其特性Per-Queue Message TTL和 Dead ...
随机推荐
- 【题解】Luogu P3287 [SCOI2014]方伯伯的玉米田
原题传送门 一眼就能看出来这是一道dp题 显而易见每次操作的右端点一定是n,每株玉米被拔高的次数随位置不下降 用f(i,j) 表示以第i 株玉米结尾它被拔高了j 次的最长序列长度. \(f(i,j)= ...
- 复旦大学2016--2017学年第一学期(16级)高等代数I期末考试第七大题解答
七.(本题10分) 设 $A,B$ 均为 $m\times n$ 阶实矩阵, 满足 $A'B+B'A=0$. 证明: $$r(A+B)\geq\max\{r(A),r(B)\},$$并且等号成立的充 ...
- JAVASCRIPT 分层概念
1)底层(框架提供): 封装DOM和Event相关操作,提供跨浏览器兼容的接口,扩展原生javascript语言本身不提供的但又特实用的接口,例如namespace; 2)抽象类层(框架提供 统一自定 ...
- 关系数据库、NoSQL和NewSQL数据库产品分类
- html5中的几种布局简单比较
html中的布局主要由静态布局.自适应布局.流式布局以及响应式布局几类,简单比较以下这几种布局的区别和特点. 一 静态布局(Static Layout) 表现:在传统web设计中,不管浏览器尺寸具体大 ...
- 谈谈如何给下拉框option添加点击事件?
我们在用到下拉列表框select时,需要对选中的<option>选项触发事件,其实<option>本身没有触发事件方法,我们只有在select里的onchange方法里触发. ...
- Android中使用Thread线程与AsyncTask异步任务的区别
最近和几个朋友交流Android开发中的网络下载问题时,谈到了用Thread开启下载线程时会产生的Bug,其实直接用子线程开启下载任务的确是很Low的做法,那么原因究竟如何,而比较高大上的做法是怎样? ...
- android Studio 出现:Unable to resolve dependency for ':app@debug/compileClasspath'
li经千辛万苦,我的新工程gradle搞定了 但是却在变异的时候告诉我 Unable to resolve dependency for ':app@debug/compileClasspath'xx ...
- pip freeze 命令迁移模块
问题描述:现有一个测试环境安装了脚本相关的各类模块,现需要不通过联网下载,在另一个环境配置安装相同的模块 解决方案: 在安装了python脚本相关的各类模块的测试环境里,进入到任意目录下,导出pyth ...
- Luffy之结算订单页面(订单模型表的创建,订单的生成,以及订单详情展示等)
订单页面 在前面我们已经构建了,购物车的页面,接下来到了结算页面 1.首先,在购物车页面点击去结算按钮时,我们需要做如下动作 .前端发送生成订单的请求,点击标签内触发事件 create_order t ...