# em-hiredis
## What
A Redis client for EventMachine designed to be fast and simple.
## Why
I wanted a client which:
* used the C hiredis library to parse redis replies
* had a convenient API for pubsub
* exposed the state of the underlying redis connections so that custom failover logic could be written outside the library
Also, <https://github.com/madsimian/em-redis> is no longer maintained.
## Getting started
Connect to redis:
require 'em-hiredis'
redis = EM::Hiredis.connect
Or, connect to redis with a redis URL (for a different host, port, password, DB)
redis = EM::Hiredis.connect("redis://:secretpassword@example.com:9000/4")
Commands may be sent immediately. Any commands sent while connecting to redis will be queued.
All redis commands are available without any remapping of names, and return a deferrable
redis.set('foo', 'bar').callback {
redis.get('foo').callback { |value|
p [:returned, value]
}
}
If redis replies with an error (for example you called a hash operation against a set or the database is full), or if the redis connection disconnects before the command returns, the deferrable will fail.
redis.sadd('aset', 'member').callback {
response_deferrable = redis.hget('aset', 'member')
response_deferrable.errback { |e|
p e # => #<EventMachine::Hiredis::RedisError: Error reply from redis (wrapped in redis_error)>
p e.redis_error # => #<RuntimeError: ERR Operation against a key holding the wrong kind of value>
}
}
As a shortcut, if you're only interested in binding to the success case you can simply provide a block to any command
redis.get('foo') { |value|
p [:returned, value]
}
## Understanding the state of the connection
When a connection to redis server closes, a `:disconnected` event will be emitted and the connection will be immediately reconnect. If the connection reconnects a `:connected` event will be emitted.
If a reconnect fails to connect, a `:reconnect_failed` event will be emitted (rather than `:disconnected`) with the number of consecutive failures, and the connection will be retried after a timeout (defaults to 0.5s, can be set via `EM::Hiredis.reconnect_timeout=`).
If a client fails to reconnect 4 consecutive times then a `:failed` event will be emitted, and any queued redis commands will be failed (otherwise they would be queued forever waiting for a reconnect).
## Pubsub
The way pubsub works in redis is that once a subscribe has been made on a connection, it's only possible to send (p)subscribe or (p)unsubscribe commands on that connection. The connection will also receive messages which are not replies to commands.
The regular `EM::Hiredis::Client` no longer understands pubsub messages - this logic has been moved to `EM::Hiredis::PubsubClient`. The pubsub client can either be initialized directly (see code) or you can get one connected to the same redis server by calling `#pubsub` on an existing `EM::Hiredis::Client` instance.
Pubsub can either be used in em-hiredis in a close-to-the-metal fashion, or you can use the convenience functionality for binding blocks to subscriptions if you prefer (recommended).
### Close to the metal pubsub interface
Basically just bind to `:message` and `:pmessage` events:
# Create two connections, one will be used for subscribing
redis = EM::Hiredis.connect
pubsub = redis.pubsub
pubsub.subscribe('bar.0').callback { puts "Subscribed" }
pubsub.psubscribe('bar.*')
pubsub.on(:message) { |channel, message|
p [:message, channel, message]
}
pubsub.on(:pmessage) { |key, channel, message|
p [:pmessage, key, channel, message]
}
EM.add_periodic_timer(1) {
redis.publish("bar.#{rand(2)}", "hello").errback { |e|
p [:publisherror, e]
}
}
### Richer pubsub interface
If you pass a block to `subscribe` or `psubscribe`, the passed block will be called whenever a message arrives on that subscription:
redis = EM::Hiredis.connect
puts "Subscribing"
redis.pubsub.subscribe("foo") { |msg|
p [:sub1, msg]
}
redis.pubsub.psubscribe("f*") { |channel, msg|
p [:sub2, msg]
}
EM.add_periodic_timer(1) {
redis.publish("foo", "Hello")
}
EM.add_timer(5) {
puts "Unsubscribing sub1"
redis.pubsub.unsubscribe("foo")
}
It's possible to subscribe to the same channel multiple time and just unsubscribe a single callback using `unsubscribe_proc` or `punsubscribe_proc`.
## Lua
You can of course call EVAL or EVALSHA directly; the following is a higher-level API.
Registering a named command on a redis client defines a ruby method with the given name on the client:
redis.register_script(:multiply, <<-END)
return redis.call('get', KEYS[1]) * ARGV[1]
END
The method can be called in a very similar way to any other redis command; the only difference is that the first argument must be an array of keys, and the second (optional) an array of values.
# Multiplies the value at key foo by 2
redis.multiply(['foo'], [2]).callback { ... }
Lua commands are submitted to redis using EVALSHA for efficiency. If redis replies with a NOSCRIPT error, the command is automatically re-submitted with EVAL; this is totally transparent to your code and the intermediate 'failure' will not be passed to your errback.
You may register scripts globally, in which case they will be available to all clients:
EM::Hiredis::Client.register_script(:multiply, <<-END)
return redis.call('get', KEYS[1]) * ARGV[1]
END
As a final convenience, it is possible to load all lua scripts from a directory automatically. All `.lua` files in the directory will be registered, and named according to filename (so a file called `sum.lua` becomes available as `redis.sum(...)`).
EM::Hiredis::Client.load_scripts_from('./lua_scripts')
For examples see `examples/lua.rb` or `lib/em-hiredis/lock_lua`.
## Inactivity checks
Sometimes a network connection may hang in ways which are difficult to detect or involve very long timeouts before they can be detected from the application layer. This is especially true of Redis Pubsub connections, as they are not request-response driven. It is very difficult for a listening client to descern between a hung connection and a server with nothing to say.
To start an application layer ping-pong mechanism for testing connection liveness, call the following at any time on a client:
redis.configure_inactivity_check(5, 3)
This configures a `PING` command to be sent if 5 seconds elapse without receiving any data from the server, and a reconnection to be triggered if a futher 3 seconds elapse after the `PING` is submitted.
This configuration is per client, you may choose different value for clients with different expected traffic patterns, or activate it on some and not at all on others.
### PING and Pubsub
Because the Redis Pubsub protocol limits the set of valid commands on a connection once it is in "Pubsub" mode, `PING` is not supported in this case (though it may be in future, see https://github.com/antirez/redis/issues/420). In order to create some valid request-response traffic on the connection, a Pubsub connection will issue `SUBSCRIBE "__em-hiredis-ping"`, followed by a corresponding `UNSUBSCRIBE` immediately on success of the subscribe.
While less than ideal, this is the case where an application layer inactivity check is most valuable, and so the trade off is reasonable until `PING` is supported correctly on Pubsub connections.
## Developing
You need bundler and a local redis server running on port 6379 to run the test suite.
# WARNING: The tests call flushdb on db 9 - this clears all keys!
bundle exec rake
Run an individual spec:
bundle exec rspec spec/redis_commands_spec.rb
Many thanks to the em-redis gem for getting this gem bootstrapped with some tests.
赵闪闪168
- 粉丝: 1726
- 资源: 6942
最新资源
- 基于粒子群算法的电动汽车充电站和光伏最优选址和定容 关键词:选址定容 电动汽车 充电站位置 仿真平台:MATLAB 主要内容:代码主要做的是一个电动汽车充电站和分布式光伏的选址定容问题,提出了
- 伺服送料机,步进电机,伺服电机,程序,三菱,台达,中达一体机,送料机程序,PLC多段数据不同,可任意调节A段B段c段长度,并定长切断 程序能存储5段工件数据,使用调出非常方便 PLC程序有台达ES
- 考虑安全约束及热备用的电力系统机组组合研究 关键词:机组组合 直流潮流 优化调度 参考文档:店主自编文档,模型数据清晰明了 仿真平台:MATLAB+CPLEX gurobi平台 优势:代码具有一定
- 计及源-荷双重不确定性的电厂 微网日前随机优化调度系统 关键词:电厂 微网 随机优化 随机调度 源-荷双重不确定性 电厂调度 参考文档:Virtual power plant mid-ter
- 基于mpc模型预测轨迹跟踪控制,总共包含两套仿真,一套是不加入四轮侧偏角软约束,一套是加入四轮侧偏角的软约束控制,通过carsim与simulink联合仿真发现加入侧偏角软约束在进行轨迹跟踪时,能够通
- 采用下垂控制的孤岛逆变器仿真 名称:droop-controlled-converter-island 软件:Matlab R2016a 控制:下垂控制,闭环电流反馈控制,解耦电压电流环控制,见图1
- 直驱式波浪发电最大功率捕获matlab仿真 电机:直线电机 控制器:PID控制器 策略:基于RLC等效电路模型的最大功率输出 含:使用说明书+教学视频
- 西门子200smart标准程序,西门子程序模板参考,3轴控制程序,含西门子触摸屏程序,详细注释,IO表,电气原理图
- 基于西门子PLC200自动保暖供水系统,系统用于厂区饮用水,区域热水保暖,系统中大多数用于时间进行各个季节,各个时间的控制 供水区域时间的设定 可以实现在每一个阶段按照每一个流程进行不同的运行
- 西门子S7-1200四层电梯模拟程序 电梯WinCC动画程序 西门子参考学习程序 博图15或者以上可以打开 PLC:西门子S7-1200 触摸屏:KTP900 有人会问:为什么是四层电梯参考学习程序
- 整车电子电气正向开发网络架构 , 倘若您是产品经理或者项目经理又或者是技术leader,这个将帮助您梳理在整车电子电气正向开发过程中不同系统的内部架构设计及相互间的关联,涵盖整车控制系统、网联系统、驾
- dsp28335三相逆变程序,可以开环测试
- 含分布式电源的无功补偿(Matlab程序): 1.以无功补偿调节代价为目标函数,不同风光电源渗透率下,优化确定无功补偿装置出力情况(改进灰狼优化算法IGWO) 2.以网损和电压偏差为目标函数,才用分
- 整车控制器 基于MPC和滑模控制算法实现的车辆稳定性控制,建立了横摆角速度、侧向速度、前后质心侧偏角动力学模型作为预测模型,同时考虑车辆的稳定性可通过控制车辆的侧向速度维持在一定范围内保证车辆的稳定性
- COMSOL MATLAB 代码 二维随机裂隙 2维随机裂隙生成 功能:可以实现多组不同方向,不同分布规律的裂隙生成(任意组数都可以) 需要输入的参数有:每组裂隙的迹长范围、分布规律(正态分布o
- 全阶滑模无位置传感器控制仿真模型,有基本的开关函数,有饱和函数,sigmod函数等多种滑模 还有全阶滑模观测器仿真,相比传统滑模观测器消除了额外的低通滤波器,误差更小,效果堪称完美 不仅误差小
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈