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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: