rainbows 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.document +1 -0
  2. data/Documentation/GNUmakefile +4 -1
  3. data/Documentation/comparison.css +6 -0
  4. data/Documentation/comparison.haml +297 -0
  5. data/GIT-VERSION-GEN +1 -1
  6. data/GNUmakefile +24 -17
  7. data/README +32 -28
  8. data/Summary +7 -0
  9. data/TODO +4 -6
  10. data/bin/rainbows +2 -2
  11. data/lib/rainbows.rb +33 -3
  12. data/lib/rainbows/actor_spawn.rb +29 -0
  13. data/lib/rainbows/app_pool.rb +17 -6
  14. data/lib/rainbows/base.rb +10 -13
  15. data/lib/rainbows/const.rb +1 -1
  16. data/lib/rainbows/dev_fd_response.rb +6 -0
  17. data/lib/rainbows/error.rb +34 -0
  18. data/lib/rainbows/ev_core.rb +3 -12
  19. data/lib/rainbows/event_machine.rb +7 -9
  20. data/lib/rainbows/fiber.rb +15 -0
  21. data/lib/rainbows/fiber/base.rb +112 -0
  22. data/lib/rainbows/fiber/io.rb +65 -0
  23. data/lib/rainbows/fiber/queue.rb +35 -0
  24. data/lib/rainbows/fiber_pool.rb +44 -0
  25. data/lib/rainbows/fiber_spawn.rb +34 -0
  26. data/lib/rainbows/http_server.rb +14 -1
  27. data/lib/rainbows/never_block.rb +69 -0
  28. data/lib/rainbows/rev.rb +7 -0
  29. data/lib/rainbows/rev/client.rb +9 -3
  30. data/lib/rainbows/rev/core.rb +2 -5
  31. data/lib/rainbows/rev/heartbeat.rb +5 -1
  32. data/lib/rainbows/rev_thread_spawn.rb +62 -60
  33. data/lib/rainbows/revactor.rb +22 -23
  34. data/lib/rainbows/thread_pool.rb +28 -26
  35. data/lib/rainbows/thread_spawn.rb +33 -33
  36. data/local.mk.sample +9 -7
  37. data/rainbows.gemspec +8 -2
  38. data/t/GNUmakefile +14 -7
  39. data/t/fork-sleep.ru +10 -0
  40. data/t/simple-http_FiberPool.ru +9 -0
  41. data/t/simple-http_FiberSpawn.ru +9 -0
  42. data/t/simple-http_NeverBlock.ru +11 -0
  43. data/t/sleep.ru +2 -0
  44. data/t/t0000-simple-http.sh +12 -1
  45. data/t/t0001-unix-http.sh +12 -1
  46. data/t/t0009-broken-app.sh +56 -0
  47. data/t/t0009.ru +13 -0
  48. data/t/t0010-keepalive-timeout-effective.sh +42 -0
  49. data/t/t0011-close-on-exec-set.sh +54 -0
  50. data/t/t0300-async_sinatra.sh +1 -1
  51. data/t/t9000-rack-app-pool.sh +1 -1
  52. data/t/t9000.ru +8 -5
  53. data/t/test-lib.sh +14 -4
  54. metadata +33 -5
  55. data/lib/rainbows/ev_thread_core.rb +0 -80
data/.document CHANGED
@@ -10,3 +10,4 @@ SIGNALS
10
10
  TODO
11
11
  TUNING
12
12
  vs_Unicorn
13
+ Summary
@@ -26,5 +26,8 @@ install-man: man
26
26
  %.1.html: %.1.txt
27
27
  $(pandoc_html) < $< > $@+ && mv $@+ $@
28
28
 
29
+ comparison.html: comparison.haml
30
+ haml -t ugly < $< > $@+ && mv $@+ $@
31
+
29
32
  clean::
30
- $(RM) $(man1) $(html1)
33
+ $(RM) $(man1) $(html1) comparison.html
@@ -0,0 +1,6 @@
1
+ /* help to make this look nice would be greatly appreciated */
2
+ .comparison {
3
+ margin: 1em;
4
+ border: 1px solid;
5
+ width: 100%;
6
+ }
@@ -0,0 +1,297 @@
1
+ %h2 core features and compatibility
2
+ %br
3
+ %table.comp
4
+ %tr.comp_header
5
+ %th.mod module
6
+ %th.tee rack.input streaming
7
+ %th.r18 Ruby 1.8
8
+ %th.r19 Ruby 1.9
9
+ %th.rbx Rubinius
10
+ %th.slow slow clients
11
+ %tr.comp_base
12
+ %td.mod Unicorn/Base
13
+ %td.tee Yes
14
+ %td.r18 Yes
15
+ %td.r19 Yes
16
+ %td.rbx Yes
17
+ %td.slow No
18
+ %tr.comp_row
19
+ %td.mod Revactor
20
+ %td.tee Yes
21
+ %td.r18 No
22
+ %td.r19 Yes
23
+ %td.rbx No
24
+ %td.slow Yes
25
+ %tr.comp_row
26
+ %td.mod ThreadPool
27
+ %td.tee Yes
28
+ %td.r18 Yes
29
+ %td.r19 Yes
30
+ %td.rbx Yes
31
+ %td.slow OK
32
+ %tr.comp_row
33
+ %td.mod Rev
34
+ %td.tee No
35
+ %td.r18 Yes
36
+ %td.r19 Yes
37
+ %td.rbx No
38
+ %td.slow Yes
39
+ %tr.comp_row
40
+ %td.mod ThreadSpawn
41
+ %td.tee Yes
42
+ %td.r18 Yes
43
+ %td.r19 Yes
44
+ %td.rbx Yes
45
+ %td.slow OK
46
+ %tr.comp_row
47
+ %td.mod EventMachine
48
+ %td.tee No
49
+ %td.r18 Yes
50
+ %td.r19 Yes
51
+ %td.rbx No
52
+ %td.slow Yes
53
+ %tr.comp_row
54
+ %td.mod RevThreadSpawn
55
+ %td.tee No
56
+ %td.r18 Slow*
57
+ %td.r19 Yes
58
+ %td.rbx No
59
+ %td.slow Yes
60
+ %tr.comp_row
61
+ %td.mod FiberSpawn
62
+ %td.tee Yes
63
+ %td.r18 No
64
+ %td.r19 Yes
65
+ %td.rbx No
66
+ %td.slow Yes
67
+ %tr.comp_row
68
+ %td.mod FiberPool
69
+ %td.tee Yes
70
+ %td.r18 No
71
+ %td.r19 Yes
72
+ %td.rbx No
73
+ %td.slow Yes
74
+ %tr.comp_base
75
+ %td.mod ActorSpawn
76
+ %td.tee Yes
77
+ %td.r18 Not yet
78
+ %td.r19 No
79
+ %td.rbx Yes
80
+ %td.slow Yes
81
+ %tr.comp_base
82
+ %td.mod NeverBlock
83
+ %td.tee No
84
+ %td.r18 Yes
85
+ %td.r19 Yes
86
+ %td.rbx No
87
+ %td.slow Yes
88
+ %ul
89
+ %li
90
+ RevThreadSpawn + 1.8 performance is being improved, follow
91
+ the
92
+ %a(href="http://rubyforge.org/mailman/listinfo/rev-talk")
93
+ rev-talk mailing list
94
+ for details.
95
+ %li
96
+ waiting on Rubinius for better signal handling
97
+ %li
98
+ rack.input streaming is what makes
99
+ %a(href="http://upr.bogomips.org/") upload progress,
100
+ BOSH, and Web Sockets possible
101
+ %li
102
+ rack.input streaming is NOT compatible with current versions of nginx
103
+ or any proxy that fully buffers request bodies before proxying.
104
+ Keep in mind request body buffering in nginx is a good thing in all
105
+ other cases where rack.input streaming is not needed.
106
+
107
+ %h2 application requirements
108
+ %br
109
+ %table.comp
110
+ %tr.comp_header
111
+ %th.mod module
112
+ %th.slowio slow I/O (backend, not client)
113
+ %th.thr thread safety
114
+ %th.reent single thread reentrant
115
+ %tr.comp_base
116
+ %td.mod Unicorn/Base
117
+ %td.slowio avoid
118
+ %td.thr No
119
+ %td.reent No
120
+ %tr.comp_row
121
+ %td.mod Revactor
122
+ %td.slowio
123
+ %a(href="http://rev.rubyforge.org/")Rev,
124
+ %a(href="http://revactor.org/")Revactor,
125
+ %b
126
+ not
127
+ %a(href="Rainbows/Fiber/IO.html")Fiber::IO
128
+ %td.thr No
129
+ %td.reent Yes
130
+ %tr.comp_row
131
+ %td.mod ThreadPool
132
+ %td.slowio thread-safe Ruby
133
+ %td.thr Yes
134
+ %td.reent No
135
+ %tr.comp_row
136
+ %td.mod Rev
137
+ %td.slowio
138
+ %a(href="http://rev.rubyforge.org/") Rev
139
+ %td.thr No
140
+ %td.reent No
141
+ %tr.comp_row
142
+ %td.mod ThreadSpawn
143
+ %td.slowio thread-safe Ruby
144
+ %td.thr Yes
145
+ %td.reent No
146
+ %tr.comp_row
147
+ %td.mod EventMachine
148
+ %td.slowio
149
+ %a(href="http://rubyeventmachine.com") EventMachine
150
+ %td.thr No
151
+ %td.reent No
152
+ %tr.comp_row
153
+ %td.mod RevThreadSpawn
154
+ %td.slowio
155
+ thread-safe Ruby,
156
+ %a(href="http://rev.rubyforge.org/") Rev
157
+ %td.thr Yes
158
+ %td.reent No
159
+ %tr.comp_row
160
+ %td.mod FiberSpawn
161
+ %td.slowio
162
+ %a(href="Rainbows/Fiber/IO.html") Rainbows::Fiber::IO
163
+ %td.thr No
164
+ %td.reent Yes
165
+ %tr.comp_row
166
+ %td.mod FiberPool
167
+ %td.slowio
168
+ %a(href="Rainbows/Fiber/IO.html") Rainbows::Fiber::IO
169
+ %td.thr No
170
+ %td.reent Yes
171
+ %tr.comp_base
172
+ %td.mod ActorSpawn
173
+ %td.slowio thread-safe Ruby
174
+ %td.thr Yes
175
+ %td.reent Yes
176
+ %tr.comp_base
177
+ %td.mod NeverBlock
178
+ %td.slowio
179
+ %a(href="http://www.espace.com.eg/neverblock") NeverBlock,
180
+ %a(href="http://rubyeventmachine.com") EventMachine
181
+ %td.thr No
182
+ %td.reent Yes
183
+
184
+ %ul
185
+ %li
186
+ Requirements for single thread reentrancy are loose in that there is
187
+ no risk of race conditions and potentially mutually exclusive to
188
+ thread-safety. In the case where a Fiber yields while holding a
189
+ resource and another Fiber attempting to acquire it may raise
190
+ an error or worse, deadlock the entire process.
191
+ %li
192
+ Slow I/O means anything that can block/stall on sockets including
193
+ 3rd-party APIs (OpenID providers included) or slow database queries.
194
+ Properly run Memcached (within the same LAN) is fast and not a blocker.
195
+ Slow I/O on POSIX filesystems only includes a few operations, namely
196
+ on UNIX domain sockets and named pipes. Nearly all other operations
197
+ on POSIX filesystems can be considered "fast", or at least
198
+ uninterruptible.
199
+
200
+ %h2 middlewares and frameworks
201
+ %br
202
+
203
+ %table.comp
204
+ %tr.comp_header
205
+ %th.mod model
206
+ %th.devfd
207
+ %a(href="Rainbows/DevFdResponse.html") DevFdResponse
208
+ %th.app_pool
209
+ %a(href="Rainbows/AppPool.html") AppPool
210
+ %th.lock
211
+ %a(href="http://rack.rubyforge.org/doc/Rack/Lock.html") Rack::Lock
212
+ %th.async async
213
+ %tr.comp_row
214
+ %td.mod Unicorn/Base
215
+ %td.devfd no-op
216
+ %td.app_pool no-op
217
+ %td.lock no-op
218
+ %td.async lots of RAM :P
219
+ %tr.comp_row
220
+ %td.mod Revactor
221
+ %td.devfd no-op
222
+ %td.app_pool Yes
223
+ %td.lock No!
224
+ %td.async Revactor itself
225
+ %tr.comp_row
226
+ %td.mod ThreadPool
227
+ %td.devfd no-op
228
+ %td.app_pool Yes
229
+ %td.lock Yes
230
+ %td.async standard Ruby
231
+ %tr.comp_row
232
+ %td.mod Rev
233
+ %td.devfd Yes
234
+ %td.app_pool no-op
235
+ %td.lock no-op
236
+ %td.async DevFdResponse
237
+ %tr.comp_row
238
+ %td.mod ThreadSpawn
239
+ %td.devfd no-op
240
+ %td.app_pool Yes
241
+ %td.lock Yes
242
+ %td.async standard Ruby
243
+ %tr.comp_row
244
+ %td.mod EventMachine
245
+ %td.devfd Yes
246
+ %td.app_pool no-op
247
+ %td.lock no-op
248
+ %td.async async_sinatra
249
+ %tr.comp_row
250
+ %td.mod RevThreadSpawn
251
+ %td.devfd Yes
252
+ %td.app_pool Yes
253
+ %td.lock Dumb
254
+ %td.async standard Ruby
255
+ %tr.comp_row
256
+ %td.mod FiberSpawn
257
+ %td.devfd Yes
258
+ %td.app_pool Yes
259
+ %td.lock No!
260
+ %td.async Rainbows::Fiber{::IO,.sleep}
261
+ %tr.comp_row
262
+ %td.mod FiberPool
263
+ %td.devfd Yes
264
+ %td.app_pool Yes
265
+ %td.lock No!
266
+ %td.async Rainbows::Fiber{::IO,.sleep}
267
+ %tr.comp_row
268
+ %td.mod ActorSpawn
269
+ %td.devfd no-op
270
+ %td.app_pool Yes
271
+ %td.lock Yes
272
+ %td.async standard Ruby
273
+ %tr.comp_row
274
+ %td.mod NeverBlock
275
+ %td.devfd Yes
276
+ %td.app_pool Yes*
277
+ %td.lock Yes*
278
+ %td.async NeverBlock, async_sinatra
279
+
280
+ %ul
281
+ %li
282
+ "No!" means it's fundamentally incompatible, use an
283
+ %a(href="Rainbows/AppPool.html") AppPool
284
+ %b :size
285
+ of one instead.
286
+ %li
287
+ NeverBlock also supports a :pool_size option which is one less
288
+ layer of complexity than using AppPool.
289
+ %li
290
+ NeverBlock can neuter the Mutex class so Rack::Lock effectively
291
+ becomes a no-op with:
292
+ %br
293
+ %code require "never_block/frameworks/rails"
294
+ (before Rails is loaded)
295
+ %li
296
+ Everything that's DevFdResponse-compatible can use it for passing
297
+ async responses through
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.6.0.GIT
4
+ DEF_VER=v0.7.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,19 +1,13 @@
1
- # use GNU Make to run tests in parallel, and without depending on Rubygems
1
+ # use GNU Make to run tests in parallel, and without depending on RubyGems
2
2
  all::
3
3
  RUBY = ruby
4
- rake = rake
4
+ RAKE = rake
5
5
  GIT_URL = git://git.bogomips.org/rainbows.git
6
6
 
7
7
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
8
8
  @./GIT-VERSION-GEN
9
9
  -include GIT-VERSION-FILE
10
10
  -include local.mk
11
- ifdef ruby
12
- ifeq ($(RUBY),ruby)
13
- $(warning ruby variable is deprecated, use RUBY instead)
14
- RUBY = $(ruby)
15
- endif
16
- endif
17
11
  ifeq ($(DLEXT),) # "so" for Linux
18
12
  DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts Config::CONFIG["DLEXT"]')
19
13
  endif
@@ -61,13 +55,16 @@ manifest: $(pkg_extra) man
61
55
  $(RM) $@+
62
56
 
63
57
  NEWS: GIT-VERSION-FILE
64
- $(rake) -s news_rdoc > $@+
58
+ $(RAKE) -s news_rdoc > $@+
65
59
  mv $@+ $@
66
60
 
67
- SINCE = 0.5.0
68
- ChangeLog: log_range = $(shell test -n "$(SINCE)" && echo v$(SINCE)..)
61
+ SINCE = 0.6.0
62
+ ChangeLog: LOG_VERSION = \
63
+ $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
64
+ echo $(GIT_VERSION) || git describe)
65
+ ChangeLog: log_range = v$(SINCE)..$(LOG_VERSION)
69
66
  ChangeLog: GIT-VERSION-FILE
70
- @echo "ChangeLog from $(GIT_URL) ($(SINCE)..$(GIT_VERSION))" > $@+
67
+ @echo "ChangeLog from $(GIT_URL) ($(log_range))" > $@+
71
68
  @echo >> $@+
72
69
  git log $(log_range) | sed -e 's/^/ /' >> $@+
73
70
  mv $@+ $@
@@ -80,6 +77,7 @@ atom = <link rel="alternate" title="Atom feed" href="$(1)" \
80
77
  # using rdoc 2.4.1+
81
78
  doc: .document NEWS ChangeLog
82
79
  for i in $(man1_bins); do > $$i; done
80
+ find bin lib -type f -name '*.rbc' -exec rm -f '{}' ';'
83
81
  rdoc -Na -t "$(shell sed -ne '1s/^= //p' README)"
84
82
  install -m644 COPYING doc/COPYING
85
83
  install -m644 $(shell grep '^[A-Z]' .document) doc/
@@ -94,8 +92,13 @@ doc: .document NEWS ChangeLog
94
92
  $(RUBY) -i -p -e \
95
93
  '$$_.gsub!("</title>",%q{\&$(call atom,$(news_atom))})' \
96
94
  doc/NEWS.html doc/README.html
97
- $(rake) -s news_atom > doc/NEWS.atom.xml
95
+ $(RAKE) -s news_atom > doc/NEWS.atom.xml
98
96
  cd doc && ln README.html tmp && mv tmp index.html
97
+ $(MAKE) -C Documentation comparison.html
98
+ $(RUBY) -i -p -e \
99
+ '$$_.gsub!(/INCLUDE/){File.read("Documentation/comparison.html")}' \
100
+ doc/Summary.html
101
+ cat Documentation/comparison.css >> doc/rdoc.css
99
102
  $(RM) $(man1_bins)
100
103
 
101
104
  ifneq ($(VERSION),)
@@ -109,10 +112,10 @@ release_changes := release_changes-$(VERSION)
109
112
  release-notes: $(release_notes)
110
113
  release-changes: $(release_changes)
111
114
  $(release_changes):
112
- $(rake) -s release_changes > $@+
115
+ $(RAKE) -s release_changes > $@+
113
116
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
114
117
  $(release_notes):
115
- GIT_URL=$(GIT_URL) $(rake) -s release_notes > $@+
118
+ GIT_URL=$(GIT_URL) $(RAKE) -s release_notes > $@+
116
119
  $(VISUAL) $@+ && test -s $@+ && mv $@+ $@
117
120
 
118
121
  # ensures we're actually on the tagged $(VERSION), only used for release
@@ -150,10 +153,14 @@ $(pkgtgz): manifest fix-perms
150
153
  package: $(pkgtgz) $(pkggem)
151
154
 
152
155
  release: verify package $(release_notes) $(release_changes)
156
+ # make tgz release on RubyForge
153
157
  rubyforge add_release -f -n $(release_notes) -a $(release_changes) \
154
158
  $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
155
- rubyforge add_file \
156
- $(rfproject) $(rfpackage) $(VERSION) $(pkgtgz)
159
+ # push gem to Gemcutter
160
+ gem push $(pkggem)
161
+ # in case of gem downloads from RubyForge releases page
162
+ -rubyforge add_file \
163
+ $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
157
164
  else
158
165
  gem install-gem: GIT-VERSION-FILE
159
166
  $(MAKE) $@ VERSION=$(GIT_VERSION)
data/README CHANGED
@@ -1,6 +1,6 @@
1
1
  = Rainbows! Unicorn for sleepy apps and slow clients
2
2
 
3
- Rainbows! is a HTTP server for sleepy Rack applications. It is based on
3
+ Rainbows! is an HTTP server for sleepy Rack applications. It is based on
4
4
  Unicorn, but designed to handle applications that expect long
5
5
  request/response times and/or slow clients. For Rack applications not
6
6
  heavily bound by slow external network dependencies, consider Unicorn
@@ -13,24 +13,23 @@ suck; differently.
13
13
 
14
14
  For network concurrency, models we currently support are:
15
15
 
16
- * {:Revactor}[link:Rainbows/Revactor.html]
17
- * {:ThreadPool}[link:Rainbows/ThreadPool.html]
18
- * {:Rev}[link:Rainbows/Rev.html]*
19
- * {:ThreadSpawn}[link:Rainbows/ThreadSpawn.html]
20
- * {:EventMachine}[link:Rainbows/EventMachine.html]
16
+ * {Revactor}[link:Rainbows/Revactor.html]
17
+ * {ThreadPool}[link:Rainbows/ThreadPool.html]
18
+ * {Rev}[link:Rainbows/Rev.html]
19
+ * {ThreadSpawn}[link:Rainbows/ThreadSpawn.html]
20
+ * {EventMachine}[link:Rainbows/EventMachine.html]
21
+ * {RevThreadSpawn}[link:Rainbows/RevThreadSpawn.html]
22
+ * {FiberSpawn}[link:Rainbows/FiberSpawn.html]
23
+ * {FiberPool}[link:Rainbows/FiberPool.html]
24
+ * {NeverBlock}[link:Rainbows/NeverBlock.html]
21
25
 
22
- We have {more on the way}[link:TODO.html] for handling network concurrency.
23
- Additionally, we also use multiple processes (managed by Unicorn) for
24
- CPU/memory/disk concurrency.
26
+ We have {many more on the way}[link:TODO.html] for handling network
27
+ concurrency. Additionally, we also use multiple processes (managed by
28
+ Unicorn) for robustness and CPU/memory/disk concurrency.
25
29
 
26
- \* our \Rev concurrency model is only recommended for slow clients, not
27
- sleepy apps. Additionally it does not support streaming "rack.input" to
28
- the application.
29
-
30
- For application concurrency, we have the Rainbows::AppPool Rack
31
- middleware that allows us to limit application concurrency independently
32
- of network concurrency. Rack::Lock as distributed by Rack may also be
33
- used to limit application concurrency to one (per-worker).
30
+ We also provide Rainbows::AppPool Rack middleware for some network
31
+ concurrency models for limiting application concurrency independently of
32
+ network concurrency.
34
33
 
35
34
  == Features
36
35
 
@@ -38,8 +37,8 @@ used to limit application concurrency to one (per-worker).
38
37
  modern Ruby HTTP applications.
39
38
 
40
39
  * Built on {Unicorn}[http://unicorn.bogomips.org/], inheriting its
41
- process/socket management features
42
- such as transparent upgrades and Ruby configuration DSL.
40
+ process/socket management features such as transparent upgrades and
41
+ Ruby configuration DSL.
43
42
 
44
43
  * As with Unicorn, it is able to stream large request bodies off the
45
44
  socket to the application while the client is still uploading. Since
@@ -47,13 +46,16 @@ used to limit application concurrency to one (per-worker).
47
46
  it is with Unicorn.
48
47
 
49
48
  * Combines heavyweight concurrency (worker processes) with lightweight
50
- concurrency (Actors or Threads), allowing CPU/memory/disk to be scaled
51
- independently of client connections. Alternative concurrency models
49
+ concurrency (Events/Fibers/Actors/Threads), allowing CPU/memory/disk to
50
+ be scaled independently of client connections. More concurrency models
52
51
  (listed in the TODO) will be supported as we find time for them.
53
52
 
53
+ * We give you {lots of options}[link:Summary.html] with more
54
+ {on the way}[link:TODO.html].
55
+
54
56
  == Applications
55
57
 
56
- \Rainbows is for the odd things Unicorn sucks at:
58
+ \Rainbows is mainly designed for the odd things Unicorn sucks at:
57
59
 
58
60
  * 3rd-party APIs (to services outside your control/LAN)
59
61
  * OpenID consumers (to providers outside your control/LAN)
@@ -63,10 +65,12 @@ used to limit application concurrency to one (per-worker).
63
65
  * BOSH (with slow clients)
64
66
  * HTTP server push
65
67
  * Long polling
66
- * Reverse Ajax
68
+ * Reverse AJAX
69
+ * HTML 5 Web Sockets
70
+ * real-time upload processing
67
71
 
68
- \Rainbows may also be used to service slow clients even with fast
69
- applications using the \Rev concurrency model.
72
+ \Rainbows can also be used to service slow clients directly even with
73
+ fast applications.
70
74
 
71
75
  == License
72
76
 
@@ -86,7 +90,7 @@ and run setup.rb after unpacking it:
86
90
 
87
91
  http://rubyforge.org/frs/?group_id=8977
88
92
 
89
- You may also install it via Rubygems on Rubyforge:
93
+ You may also install it via RubyGems on Gemcutter:
90
94
 
91
95
  gem install rainbows
92
96
 
@@ -125,13 +129,13 @@ You can get the latest source via git from the following locations
125
129
  (these versions may not be stable):
126
130
 
127
131
  git://git.bogomips.org/rainbows.git
128
- git://rubyforge.org/rainbows.git (mirror)
132
+ git://repo.or.cz/rainbows.git (mirror)
129
133
 
130
134
  You may browse the code from the web and download the latest snapshot
131
135
  tarballs here:
132
136
 
133
137
  * http://git.bogomips.org/cgit/rainbows.git (cgit)
134
- * http://rainbows.rubyforge.org/git?p=rainbows.git (gitweb)
138
+ * http://repo.or.cz/w/rainbows.git (gitweb)
135
139
 
136
140
  Inline patches (from "git format-patch") to the mailing list are
137
141
  preferred because they allow code review and comments in the reply to