mizuno 0.5.1 → 0.6.0

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.
data/README.markdown CHANGED
@@ -11,27 +11,23 @@ container for your Rack application to run under JRuby, because Mizuno
11
11
  works just like Mongrel, WEBRick, Thin, or any other standard Rack
12
12
  handler.
13
13
 
14
- Mizuno is the fastest option for Rack applications on JRuby:
15
-
16
- Mizuno: 6106.66 req/s (mean)
17
- Jetty (via jruby-rack): 2011.67 req/s (mean)
18
- Mongrel: 1479.15 req/sec (mean)
19
-
20
14
  Mizuno also supports asynchronous request handling, via the Java Servlet
21
15
  3.0 asynchronous processing mechanism
22
16
 
23
- All the speed comes from Jetty 7; Mizuno just ties it to Rack through
17
+ All the speed comes from Jetty 8; Mizuno just ties it to Rack through
24
18
  JRuby's Ruby/Java integration layer.
25
19
 
26
20
  Note that Mizuno is NOT a direct replacement for jruby-rack or Warbler,
27
21
  because it doesn't produce WAR files or make any attempt to package a
28
22
  Rack application for installation in a Java web container.
29
23
 
30
- There's also a few features that I have yet to implement:
24
+ You can also run Mizuno via rackup:
25
+
26
+ rackup -s mizuno
27
+
28
+ Or with live reloading support:
31
29
 
32
- 1. Route Jetty's logs into Rack::Logger.
33
- 2. Add hooks for realtime monitoring of server performance.
34
- 3. Fast restarts of the Rack application.
30
+ mizuno --reloadable
35
31
 
36
32
  Mizuno is licensed under the Apache Public License, version 2.0; see
37
33
  the LICENSE file for details, and was developed on behalf of
data/Rakefile CHANGED
@@ -6,6 +6,8 @@ RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :default => :spec
8
8
 
9
+ # http://rubydoc.info/gems/pompompom/1.1.3/frames
10
+
9
11
  namespace :jetty do
10
12
  desc "Grab the latest Jetty from its Maven repository."
11
13
  task :update do
@@ -40,15 +42,15 @@ namespace :jetty do
40
42
  # Inventory contents of the tarball we picked up.
41
43
  inventory = `tar tzf #{tempfile}`.split(/\n/)
42
44
 
43
- # Find replacements from our downloaded tarball for each of our jars.
45
+ # Figure out which JARs we should replce with tarball contents.
44
46
  replacements = {}
45
47
  Dir.entries(jar_path).each do |entry|
46
- next unless (entry =~ /^\w.*\d\.jar$/)
48
+ next unless ((entry =~ /^jetty-\w.*\d\.jar$/) \
49
+ or (entry =~ /^servlet-api.*\d\.jar$/))
47
50
  name = entry.sub(/\-\d.*$/, '')
48
51
  matcher = /\/#{name}\-[^\/]+\d\.jar$/
49
52
  archive_file = inventory.find { |i| i =~ matcher }
50
- raise("Archive missing replacement for #{entry}") \
51
- unless archive_file
53
+ next unless archive_file
52
54
  replacements[entry] = archive_file
53
55
  end
54
56
 
Binary file
Binary file
@@ -76,7 +76,7 @@ Choice.options do
76
76
  end
77
77
 
78
78
  separator ''
79
- separator 'Daemonization: '
79
+ separator 'Mizuno-specific options: '
80
80
 
81
81
  option :daemonize do
82
82
  short '-D'
@@ -105,7 +105,13 @@ Choice.options do
105
105
 
106
106
  option :reload do
107
107
  long '--reload'
108
- desc 'reload a running daemon'
108
+ desc 'reloads a running mizuno instance'
109
+ default false
110
+ end
111
+
112
+ option :reloadable do
113
+ long '--reloadable'
114
+ desc 'sets up live reloading via mizuno/reloader'
109
115
  default false
110
116
  end
111
117
 
@@ -1,5 +1,6 @@
1
1
  require 'mizuno/version'
2
2
  require 'mizuno/java_logger'
3
+ require 'mizuno/reloader'
3
4
 
4
5
  module Mizuno
5
6
  class HttpServer
@@ -73,6 +74,11 @@ module Mizuno
73
74
  app_handler = ServletContextHandler.new(nil, "/",
74
75
  ServletContextHandler::NO_SESSIONS)
75
76
 
77
+ # Optionally wrap with Mizuno::Reloader.
78
+ threshold = (ENV['RACK_ENV'] == 'production' ? 10 : 1)
79
+ app = Mizuno::Reloader.new(app, threshold) \
80
+ if options[:reloadable]
81
+
76
82
  # The servlet itself.
77
83
  rack_servlet = RackServlet.new
78
84
  rack_servlet.rackup(app)
@@ -175,8 +181,5 @@ module Mizuno
175
181
  end
176
182
  end
177
183
 
178
- # Register ourselves with Rack when this file gets loaded.
179
- Rack::Handler.register 'mizuno', 'Mizuno::HttpServer'
180
-
181
184
  # Ensure that we shutdown the server on exit.
182
185
  at_exit { Mizuno::HttpServer.stop }
@@ -0,0 +1,147 @@
1
+ require 'pathname'
2
+ require 'thread'
3
+
4
+ #:nodoc:
5
+ module Mizuno
6
+ #
7
+ # Middleware for reloading production applications; works exactly
8
+ # like Rack::Reloader, but rather than checking for any changed
9
+ # file, only looks at one specific file.
10
+ #
11
+ # Also allows for explicit reloading via a class method, as well as
12
+ # by sending a SIGHUP to the process.
13
+ #
14
+ class Reloader
15
+ class << self
16
+ attr_accessor :logger, :trigger, :reloaders
17
+ end
18
+
19
+ def Reloader.reload!
20
+ reloaders.each { |r| r.reload!(true) }
21
+ end
22
+
23
+ def initialize(app, interval = 1)
24
+ Thread.exclusive do
25
+ self.class.reloaders ||= []
26
+ self.class.reloaders << self
27
+ self.class.logger ||= Mizuno::HttpServer.logger
28
+ self.class.trigger ||= "tmp/restart.txt"
29
+ end
30
+
31
+ @app = app
32
+ @interval = interval
33
+ @trigger = self.class.trigger
34
+ @logger = self.class.logger
35
+ @updated = @threshold = Time.now.to_i
36
+ end
37
+
38
+ #
39
+ # Reload @app on request.
40
+ #
41
+ def call(env)
42
+ Thread.exclusive { reload! }
43
+ @app.call(env)
44
+ end
45
+
46
+ #
47
+ # Reloads the application if (a) we haven't reloaded in
48
+ # @interval seconds, (b) the trigger file has been touched
49
+ # since our last check, and (c) some other thread hasn't handled
50
+ # the update.
51
+ #
52
+ def reload!(force = false)
53
+ return unless (Time.now.to_i > @threshold)
54
+ @threshold = Time.now.to_i + @interval
55
+ return unless (force or \
56
+ ((timestamp = mtime(@trigger)).to_i > @updated))
57
+ timestamp ||= Time.now.to_i
58
+
59
+ # Check updated files to ensure they're loadable.
60
+ missing, errors = 0, 0
61
+ files = find_files_for_reload do |file, file_mtime|
62
+ next(missing += 1 and nil) unless file_mtime
63
+ next unless (file_mtime >= @updated)
64
+ next(errors += 1 and nil) unless verify(file)
65
+ file
66
+ end
67
+
68
+ # Cowardly fail if we can't load something.
69
+ @logger.debug("#{missing} files missing during reload.") \
70
+ if (missing > 0)
71
+ return(@logger.error("#{errors} errors, not reloading.")) \
72
+ if (errors > 0)
73
+
74
+ # Reload everything that's changed.
75
+ files.each do |file|
76
+ next unless file
77
+ @logger.info("Reloading #{file}")
78
+ load(file)
79
+ end
80
+ @updated = timestamp
81
+ end
82
+
83
+ #
84
+ # Walk through the list of every file we've loaded.
85
+ #
86
+ def find_files_for_reload
87
+ paths = [ './', *$LOAD_PATH ].uniq
88
+ [ $0, *$LOADED_FEATURES ].uniq.map do |file|
89
+ next if file =~ /\.(so|bundle)$/
90
+ yield(find(file, paths))
91
+ end
92
+ end
93
+
94
+ #
95
+ # Returns true if the file is loadable; uses the wrapper
96
+ # functionality of Kernel#load to protect the global namespace.
97
+ #
98
+ def verify(file)
99
+ begin
100
+ @logger.debug("Verifying #{file}")
101
+ load(file, true)
102
+ return(true)
103
+ rescue => error
104
+ @logger.error("Failed to verify #{file}: #{error.to_s}")
105
+ error.backtrace.each { |l| @logger.error(" #{l}") }
106
+ end
107
+ end
108
+
109
+ #
110
+ # Takes a relative or absolute +file+ name, a couple possible
111
+ # +paths+ that the +file+ might reside in. Returns a tuple of
112
+ # the full path where the file was found and its modification
113
+ # time, or nil if not found.
114
+ #
115
+ def find(file, paths)
116
+ if(Pathname.new(file).absolute?)
117
+ return unless (timestamp = mtime(file))
118
+ @logger.debug("Found #{file}")
119
+ [ file, timestamp ]
120
+ else
121
+ paths.each do |path|
122
+ fullpath = File.expand_path((File.join(path, file)))
123
+ next unless (timestamp = mtime(fullpath))
124
+ @logger.debug("Found #{file} in #{fullpath}")
125
+ return([ fullpath, timestamp ])
126
+ end
127
+ return(nil)
128
+ end
129
+ end
130
+
131
+ #
132
+ # Returns the modification time of _file_.
133
+ #
134
+ def mtime(file)
135
+ begin
136
+ return unless file
137
+ stat = File.stat(file)
138
+ stat.file? ? stat.mtime.to_i : nil
139
+ rescue Errno::ENOENT, Errno::ENOTDIR
140
+ nil
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ # Reload on SIGHUP.
147
+ trap("SIGHUP") { Mizuno::Reloader.reload! }
data/lib/mizuno/runner.rb CHANGED
@@ -8,6 +8,59 @@ require 'etc'
8
8
  require 'rack'
9
9
 
10
10
  module Mizuno
11
+ require 'rbconfig'
12
+
13
+ module Daemonizer
14
+ def self.included?(base)
15
+ if(Config::CONFIG['host_os'] =~ /mswin|mingw/)
16
+ base.send(:extend, StubbedClassMethods)
17
+ else
18
+ base.send(:extend, UnixClassMethods)
19
+ base.send(:class_eval) do
20
+ extend FFI::Library
21
+ ffi_lib 'c'
22
+ attach_function :_setuid, :setuid, [ :uint ], :int
23
+ attach_function :_setgid, :setgid, [ :uint ], :int
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ module UnixClassMethods
30
+ #
31
+ # Switch the process over to a new user id; will abort the
32
+ # process if it fails. _options_ is the full list of options
33
+ # passed to a server.
34
+ #
35
+ def setuid(options)
36
+ entry = Etc.getpwnam(options[:user])
37
+ die("Can't find --user named '#{options[:user]}'") \
38
+ unless entry
39
+ return unless (_setuid(entry.uid) != 0)
40
+ die("Can't switch to user '#{options[:user]}'")
41
+ end
42
+
43
+ #
44
+ # Like setuid, but for groups.
45
+ #
46
+ def setgid(options)
47
+ entry = Etc.getgrnam(options[:group])
48
+ die("Can't find --group named '#{options[:group]}'") \
49
+ unless entry
50
+ return unless (_setgid(entry.gid) != 0)
51
+ die("Can't switch to group '#{options[:group]}'")
52
+ end
53
+ end
54
+
55
+ module StubbedClassMethods
56
+ def setuid(options)
57
+ end
58
+
59
+ def setgid(options)
60
+ end
61
+ end
62
+ end
63
+
11
64
  #
12
65
  # Launches Mizuno when called from the command-line, and handles
13
66
  # damonization via FFI.
@@ -15,35 +68,7 @@ module Mizuno
15
68
  # Daemonization code based on Spoon.
16
69
  #
17
70
  class Runner
18
- extend FFI::Library
19
-
20
- ffi_lib 'c'
21
-
22
- attach_function :_setuid, :setuid, [ :uint ], :int
23
-
24
- attach_function :_setgid, :setgid, [ :uint ], :int
25
-
26
- #
27
- # Switch the process over to a new user id; will abort the
28
- # process if it fails. _options_ is the full list of options
29
- # passed to a server.
30
- #
31
- def Runner.setuid(options)
32
- entry = Etc.getpwnam(options[:user])
33
- die("Can't find --user named '#{options[:user]}'") unless entry
34
- return unless (_setuid(entry.uid) != 0)
35
- die("Can't switch to user '#{options[:user]}'")
36
- end
37
-
38
- #
39
- # Like setuid, but for groups.
40
- #
41
- def Runner.setgid(options)
42
- entry = Etc.getgrnam(options[:group])
43
- die("Can't find --group named '#{options[:group]}'") unless entry
44
- return unless (_setgid(entry.gid) != 0)
45
- die("Can't switch to group '#{options[:group]}'")
46
- end
71
+ include Daemonizer
47
72
 
48
73
  #
49
74
  # Launch Jetty, optionally as a daemon.
@@ -75,6 +100,7 @@ module Mizuno
75
100
  # Fire up Mizuno as if it was called from Rackup.
76
101
  Dir.chdir(options[:root])
77
102
  HttpServer.configure_logging(options)
103
+ ENV['RACK_ENV'] = options[:env]
78
104
  server = Rack::Server.new
79
105
  server.options = options.merge(:server => 'mizuno',
80
106
  :environment => options[:env])
@@ -105,7 +131,7 @@ module Mizuno
105
131
  File.open(options[:pidfile], 'w') { |f| f.puts(child.pid) }
106
132
 
107
133
  # Wait until the server starts or we time out waiting for it.
108
- exit if wait_for_server(options)
134
+ exit if wait_for_server(options, 60)
109
135
  child.stop
110
136
  die("Failed to start Mizuno.")
111
137
  end
@@ -1,3 +1,3 @@
1
1
  module Mizuno
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -0,0 +1,4 @@
1
+ require 'mizuno'
2
+
3
+ # Register ourselves with Rack when this file gets loaded.
4
+ Rack::Handler.register 'mizuno', 'Mizuno::HttpServer'
data/mizuno.gemspec CHANGED
@@ -23,9 +23,11 @@ Gem::Specification.new do |spec|
23
23
  lib/mizuno/java_logger.rb
24
24
  lib/mizuno/rack/chunked.rb
25
25
  lib/mizuno/rack_servlet.rb
26
+ lib/mizuno/reloader.rb
26
27
  lib/mizuno/runner.rb
27
28
  lib/mizuno/version.rb
28
29
  lib/mizuno.rb
30
+ lib/rack/handler/mizuno.rb
29
31
  bin/mizuno)
30
32
  jars = Dir.entries("lib/java").grep(/\.jar$/)
31
33
  spec.files.concat(jars.map { |j| "lib/java/#{j}" })
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: mizuno
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.1
5
+ version: 0.6.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Don Werve
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-02-17 00:00:00 Z
13
+ date: 2012-04-09 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -120,19 +120,21 @@ files:
120
120
  - lib/mizuno/java_logger.rb
121
121
  - lib/mizuno/rack/chunked.rb
122
122
  - lib/mizuno/rack_servlet.rb
123
+ - lib/mizuno/reloader.rb
123
124
  - lib/mizuno/runner.rb
124
125
  - lib/mizuno/version.rb
125
126
  - lib/mizuno.rb
127
+ - lib/rack/handler/mizuno.rb
126
128
  - bin/mizuno
127
- - lib/java/jetty-continuation-8.0.4.v20111024.jar
128
- - lib/java/jetty-http-8.0.4.v20111024.jar
129
- - lib/java/jetty-io-8.0.4.v20111024.jar
130
- - lib/java/jetty-jmx-8.0.4.v20111024.jar
131
- - lib/java/jetty-security-8.0.4.v20111024.jar
132
- - lib/java/jetty-server-8.0.4.v20111024.jar
133
- - lib/java/jetty-servlet-8.0.4.v20111024.jar
134
- - lib/java/jetty-servlets-8.0.4.v20111024.jar
135
- - lib/java/jetty-util-8.0.4.v20111024.jar
129
+ - lib/java/jetty-continuation-8.1.2.v20120308.jar
130
+ - lib/java/jetty-http-8.1.2.v20120308.jar
131
+ - lib/java/jetty-io-8.1.2.v20120308.jar
132
+ - lib/java/jetty-jmx-8.1.2.v20120308.jar
133
+ - lib/java/jetty-security-8.1.2.v20120308.jar
134
+ - lib/java/jetty-server-8.1.2.v20120308.jar
135
+ - lib/java/jetty-servlet-8.1.2.v20120308.jar
136
+ - lib/java/jetty-servlets-8.1.2.v20120308.jar
137
+ - lib/java/jetty-util-8.1.2.v20120308.jar
136
138
  - lib/java/log4j-1.2.16.jar
137
139
  - lib/java/rewindable-input-stream.jar
138
140
  - lib/java/servlet-api-3.0.jar
Binary file
Binary file