firehose 0.2.alpha.6 → 0.2.alpha.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  module Firehose
2
2
  class Publisher
3
+
3
4
  MAX_MESSAGES = 100
4
5
  TTL = 60*60*24 # 1 day of time, yay!
5
6
  PAYLOAD_DELIMITER = "\n"
@@ -14,29 +15,17 @@ module Firehose
14
15
  deferrable = EM::DefaultDeferrable.new
15
16
  deferrable.errback {|e| EM.next_tick { raise e } }
16
17
 
17
- # DRY up keys a little bit for the epic publish command to come.
18
- list_key = key(channel_key, :list)
19
- sequence_key = key(channel_key, :sequence)
20
-
21
- redis.eval(%(local current_sequence = redis.call('get', KEYS[1])
22
- if (current_sequence == nil) or (current_sequence == false)
23
- then
24
- current_sequence = 0
25
- end
26
- local sequence = current_sequence + 1
27
- redis.call('set', KEYS[1], sequence)
28
- redis.call('expire', KEYS[1], #{ttl})
29
- redis.call('lpush', KEYS[2], "#{lua_escape(message)}")
30
- redis.call('ltrim', KEYS[2], 0, #{MAX_MESSAGES - 1})
31
- redis.call('expire', KEYS[2], #{ttl})
32
- redis.call('publish', KEYS[3], "#{lua_escape(channel_key + PAYLOAD_DELIMITER)}" .. sequence .. "#{lua_escape(PAYLOAD_DELIMITER + message)}")
33
- return sequence
34
- ), 3, sequence_key, list_key, key(:channel_updates)).
35
- errback{|e| deferrable.fail e }.
36
- callback do |sequence|
37
- Firehose.logger.debug "Redis stored/published `#{message}` to list `#{list_key}` with sequence `#{sequence}`"
38
- deferrable.succeed
18
+ if @publish_script_digest.nil?
19
+ register_publish_script.errback do |e|
20
+ deferrable.fail e
21
+ end.callback do |digest|
22
+ @publish_script_digest = digest
23
+ Firehose.logger.debug "Registered Lua publishing script with Redis => #{digest}"
24
+ eval_publish_script channel_key, message, ttl, deferrable
39
25
  end
26
+ else
27
+ eval_publish_script channel_key, message, ttl, deferrable
28
+ end
40
29
 
41
30
  deferrable
42
31
  end
@@ -64,5 +53,61 @@ module Firehose
64
53
  def lua_escape(str)
65
54
  str.gsub(/\\/,'\\\\\\').gsub(/"/,'\"').gsub(/\n/,'\n').gsub(/\r/,'\r')
66
55
  end
56
+
57
+ def register_publish_script
58
+ redis.script 'LOAD', REDIS_PUBLISH_SCRIPT
59
+ end
60
+
61
+ def eval_publish_script(channel_key, message, ttl, deferrable)
62
+ list_key = key(channel_key, :list)
63
+ script_args = [
64
+ key(channel_key, :sequence),
65
+ list_key,
66
+ key(:channel_updates),
67
+ ttl,
68
+ message,
69
+ MAX_MESSAGES,
70
+ PAYLOAD_DELIMITER,
71
+ channel_key
72
+ ]
73
+ # Firehose.logger.debug "Evaluating Lua publishing script (#{@publish_script_digest}) with arguments: #{script_args.inspect}"
74
+ redis.evalsha(
75
+ @publish_script_digest, script_args.length, *script_args
76
+ ).errback do |e|
77
+ deferrable.fail e
78
+ end.callback do |sequence|
79
+ Firehose.logger.debug "Redis stored/published `#{message}` to list `#{list_key}` with sequence `#{sequence}`"
80
+ deferrable.succeed
81
+ end
82
+ end
83
+
84
+ REDIS_PUBLISH_SCRIPT = <<-LUA
85
+ local sequence_key = KEYS[1]
86
+ local list_key = KEYS[2]
87
+ local channel_key = KEYS[3]
88
+ local ttl = KEYS[4]
89
+ local message = KEYS[5]
90
+ local max_messages = KEYS[6]
91
+ local payload_delimiter = KEYS[7]
92
+ local firehose_resource = KEYS[8]
93
+
94
+ local current_sequence = redis.call('get', sequence_key)
95
+ if current_sequence == nil or current_sequence == false then
96
+ current_sequence = 0
97
+ end
98
+
99
+ local sequence = current_sequence + 1
100
+ local message_payload = firehose_resource .. payload_delimiter .. sequence .. payload_delimiter .. message
101
+
102
+ redis.call('set', sequence_key, sequence)
103
+ redis.call('expire', sequence_key, ttl)
104
+ redis.call('lpush', list_key, message)
105
+ redis.call('ltrim', list_key, 0, max_messages - 1)
106
+ redis.call('expire', list_key, ttl)
107
+ redis.call('publish', channel_key, message_payload)
108
+
109
+ return sequence
110
+ LUA
111
+
67
112
  end
68
113
  end
@@ -1,4 +1,4 @@
1
1
  module Firehose
2
- VERSION = "0.2.alpha.6"
3
- CODENAME = "Web Sockets, Schmeb Schmockets"
2
+ VERSION = "0.2.alpha.7"
3
+ CODENAME = "Look ma', no Redis/Lua memory leak!"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firehose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.alpha.6
4
+ version: 0.2.alpha.7
5
5
  prerelease: 4
6
6
  platform: ruby
7
7
  authors:
@@ -12,11 +12,11 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-08-28 00:00:00.000000000 Z
15
+ date: 2012-09-06 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: eventmachine
19
- requirement: &70256291491020 !ruby/object:Gem::Requirement
19
+ requirement: &70165766290180 !ruby/object:Gem::Requirement
20
20
  none: false
21
21
  requirements:
22
22
  - - ! '>='
@@ -24,10 +24,10 @@ dependencies:
24
24
  version: 1.0.0.rc
25
25
  type: :runtime
26
26
  prerelease: false
27
- version_requirements: *70256291491020
27
+ version_requirements: *70165766290180
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: em-hiredis
30
- requirement: &70256291490580 !ruby/object:Gem::Requirement
30
+ requirement: &70165766289740 !ruby/object:Gem::Requirement
31
31
  none: false
32
32
  requirements:
33
33
  - - ! '>='
@@ -35,10 +35,10 @@ dependencies:
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
- version_requirements: *70256291490580
38
+ version_requirements: *70165766289740
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: thor
41
- requirement: &70256291490080 !ruby/object:Gem::Requirement
41
+ requirement: &70165766289240 !ruby/object:Gem::Requirement
42
42
  none: false
43
43
  requirements:
44
44
  - - ! '>='
@@ -46,10 +46,10 @@ dependencies:
46
46
  version: '0'
47
47
  type: :runtime
48
48
  prerelease: false
49
- version_requirements: *70256291490080
49
+ version_requirements: *70165766289240
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: faraday
52
- requirement: &70256291489660 !ruby/object:Gem::Requirement
52
+ requirement: &70165766288720 !ruby/object:Gem::Requirement
53
53
  none: false
54
54
  requirements:
55
55
  - - ! '>='
@@ -57,10 +57,10 @@ dependencies:
57
57
  version: '0'
58
58
  type: :runtime
59
59
  prerelease: false
60
- version_requirements: *70256291489660
60
+ version_requirements: *70165766288720
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: faye-websocket
63
- requirement: &70256291489240 !ruby/object:Gem::Requirement
63
+ requirement: &70165766288280 !ruby/object:Gem::Requirement
64
64
  none: false
65
65
  requirements:
66
66
  - - ! '>='
@@ -68,10 +68,10 @@ dependencies:
68
68
  version: '0'
69
69
  type: :runtime
70
70
  prerelease: false
71
- version_requirements: *70256291489240
71
+ version_requirements: *70165766288280
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: em-http-request
74
- requirement: &70256291488740 !ruby/object:Gem::Requirement
74
+ requirement: &70165766287720 !ruby/object:Gem::Requirement
75
75
  none: false
76
76
  requirements:
77
77
  - - ~>
@@ -79,10 +79,10 @@ dependencies:
79
79
  version: 1.0.0
80
80
  type: :runtime
81
81
  prerelease: false
82
- version_requirements: *70256291488740
82
+ version_requirements: *70165766287720
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: json
85
- requirement: &70256291488320 !ruby/object:Gem::Requirement
85
+ requirement: &70165766287300 !ruby/object:Gem::Requirement
86
86
  none: false
87
87
  requirements:
88
88
  - - ! '>='
@@ -90,10 +90,10 @@ dependencies:
90
90
  version: '0'
91
91
  type: :runtime
92
92
  prerelease: false
93
- version_requirements: *70256291488320
93
+ version_requirements: *70165766287300
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: rspec
96
- requirement: &70256291487860 !ruby/object:Gem::Requirement
96
+ requirement: &70165766286840 !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ! '>='
@@ -101,10 +101,10 @@ dependencies:
101
101
  version: '0'
102
102
  type: :development
103
103
  prerelease: false
104
- version_requirements: *70256291487860
104
+ version_requirements: *70165766286840
105
105
  - !ruby/object:Gem::Dependency
106
106
  name: webmock
107
- requirement: &70256291459520 !ruby/object:Gem::Requirement
107
+ requirement: &70165766604500 !ruby/object:Gem::Requirement
108
108
  none: false
109
109
  requirements:
110
110
  - - ! '>='
@@ -112,10 +112,10 @@ dependencies:
112
112
  version: '0'
113
113
  type: :development
114
114
  prerelease: false
115
- version_requirements: *70256291459520
115
+ version_requirements: *70165766604500
116
116
  - !ruby/object:Gem::Dependency
117
117
  name: guard-rspec
118
- requirement: &70256291459080 !ruby/object:Gem::Requirement
118
+ requirement: &70165766603880 !ruby/object:Gem::Requirement
119
119
  none: false
120
120
  requirements:
121
121
  - - ! '>='
@@ -123,10 +123,10 @@ dependencies:
123
123
  version: '0'
124
124
  type: :development
125
125
  prerelease: false
126
- version_requirements: *70256291459080
126
+ version_requirements: *70165766603880
127
127
  - !ruby/object:Gem::Dependency
128
128
  name: guard-bundler
129
- requirement: &70256291458660 !ruby/object:Gem::Requirement
129
+ requirement: &70165766603280 !ruby/object:Gem::Requirement
130
130
  none: false
131
131
  requirements:
132
132
  - - ! '>='
@@ -134,10 +134,10 @@ dependencies:
134
134
  version: '0'
135
135
  type: :development
136
136
  prerelease: false
137
- version_requirements: *70256291458660
137
+ version_requirements: *70165766603280
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: guard-coffeescript
140
- requirement: &70256291458220 !ruby/object:Gem::Requirement
140
+ requirement: &70165766602860 !ruby/object:Gem::Requirement
141
141
  none: false
142
142
  requirements:
143
143
  - - ! '>='
@@ -145,10 +145,10 @@ dependencies:
145
145
  version: '0'
146
146
  type: :development
147
147
  prerelease: false
148
- version_requirements: *70256291458220
148
+ version_requirements: *70165766602860
149
149
  - !ruby/object:Gem::Dependency
150
150
  name: rainbows
151
- requirement: &70256291457800 !ruby/object:Gem::Requirement
151
+ requirement: &70165766602440 !ruby/object:Gem::Requirement
152
152
  none: false
153
153
  requirements:
154
154
  - - ! '>='
@@ -156,10 +156,10 @@ dependencies:
156
156
  version: '0'
157
157
  type: :development
158
158
  prerelease: false
159
- version_requirements: *70256291457800
159
+ version_requirements: *70165766602440
160
160
  - !ruby/object:Gem::Dependency
161
161
  name: thin
162
- requirement: &70256291457380 !ruby/object:Gem::Requirement
162
+ requirement: &70165766602000 !ruby/object:Gem::Requirement
163
163
  none: false
164
164
  requirements:
165
165
  - - ! '>='
@@ -167,10 +167,10 @@ dependencies:
167
167
  version: '0'
168
168
  type: :development
169
169
  prerelease: false
170
- version_requirements: *70256291457380
170
+ version_requirements: *70165766602000
171
171
  - !ruby/object:Gem::Dependency
172
172
  name: rack-test
173
- requirement: &70256291456960 !ruby/object:Gem::Requirement
173
+ requirement: &70165766601580 !ruby/object:Gem::Requirement
174
174
  none: false
175
175
  requirements:
176
176
  - - ! '>='
@@ -178,10 +178,10 @@ dependencies:
178
178
  version: '0'
179
179
  type: :development
180
180
  prerelease: false
181
- version_requirements: *70256291456960
181
+ version_requirements: *70165766601580
182
182
  - !ruby/object:Gem::Dependency
183
183
  name: async_rack_test
184
- requirement: &70256291456520 !ruby/object:Gem::Requirement
184
+ requirement: &70165766601140 !ruby/object:Gem::Requirement
185
185
  none: false
186
186
  requirements:
187
187
  - - ! '>='
@@ -189,10 +189,10 @@ dependencies:
189
189
  version: '0'
190
190
  type: :development
191
191
  prerelease: false
192
- version_requirements: *70256291456520
192
+ version_requirements: *70165766601140
193
193
  - !ruby/object:Gem::Dependency
194
194
  name: foreman
195
- requirement: &70256291456040 !ruby/object:Gem::Requirement
195
+ requirement: &70165766600720 !ruby/object:Gem::Requirement
196
196
  none: false
197
197
  requirements:
198
198
  - - ! '>='
@@ -200,10 +200,10 @@ dependencies:
200
200
  version: '0'
201
201
  type: :development
202
202
  prerelease: false
203
- version_requirements: *70256291456040
203
+ version_requirements: *70165766600720
204
204
  - !ruby/object:Gem::Dependency
205
205
  name: sprockets
206
- requirement: &70256291455540 !ruby/object:Gem::Requirement
206
+ requirement: &70165766600300 !ruby/object:Gem::Requirement
207
207
  none: false
208
208
  requirements:
209
209
  - - ! '>='
@@ -211,7 +211,7 @@ dependencies:
211
211
  version: '0'
212
212
  type: :development
213
213
  prerelease: false
214
- version_requirements: *70256291455540
214
+ version_requirements: *70165766600300
215
215
  description: Firehose is a realtime web application toolkit for building realtime
216
216
  Ruby web applications.
217
217
  email:
@@ -297,7 +297,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
297
297
  version: '0'
298
298
  segments:
299
299
  - 0
300
- hash: 1005777279219714638
300
+ hash: -2464332796124160988
301
301
  required_rubygems_version: !ruby/object:Gem::Requirement
302
302
  none: false
303
303
  requirements: