hayabusa 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/hayabusa_fcgi.fcgi +3 -4
- data/bin/hayabusa_fcgi.rb +3 -4
- data/bin/hayabusa_fcgi_server.rb +63 -0
- data/bin/hayabusa_spec_restart.rb +17 -0
- data/hayabusa.gemspec +6 -3
- data/lib/hayabusa.rb +19 -22
- data/lib/hayabusa_cgi_tools.rb +8 -2
- data/lib/hayabusa_client_session.rb +3 -1
- data/lib/hayabusa_ext/cleaner.rb +18 -18
- data/lib/hayabusa_ext/errors.rb +3 -3
- data/lib/hayabusa_ext/logging.rb +5 -5
- data/lib/hayabusa_ext/mailing.rb +14 -14
- data/lib/hayabusa_ext/sessions.rb +1 -1
- data/lib/hayabusa_ext/threadding.rb +37 -18
- data/lib/hayabusa_fcgi.rb +38 -10
- data/lib/hayabusa_fcgi_server.rb +30 -0
- data/lib/hayabusa_http_server.rb +6 -1
- data/lib/hayabusa_http_session.rb +4 -5
- data/lib/hayabusa_http_session_request.rb +1 -1
- data/pages/spec_thread_joins.rhtml +18 -3
- data/spec/fcgi_multiple_processes_spec.rb +1 -1
- metadata +8 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.14
|
data/bin/hayabusa_fcgi.fcgi
CHANGED
@@ -17,10 +17,9 @@ begin
|
|
17
17
|
require "fileutils"
|
18
18
|
|
19
19
|
#Try to load development-version to enable debugging without doing constant gem-installations.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
else
|
20
|
+
begin
|
21
|
+
require "#{File.realpath(File.dirname(__FILE__))}/../../knjrbfw/lib/knjrbfw.rb"
|
22
|
+
rescue LoadError
|
24
23
|
require "knjrbfw"
|
25
24
|
end
|
26
25
|
|
data/bin/hayabusa_fcgi.rb
CHANGED
@@ -17,10 +17,9 @@ begin
|
|
17
17
|
require "fileutils"
|
18
18
|
|
19
19
|
#Try to load development-version to enable debugging without doing constant gem-installations.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
else
|
20
|
+
begin
|
21
|
+
require "#{File.realpath(File.dirname(__FILE__))}/../../knjrbfw/lib/knjrbfw.rb"
|
22
|
+
rescue LoadError
|
24
23
|
require "knjrbfw"
|
25
24
|
end
|
26
25
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#This script starts the Hayabusa-server that the FCGI-instances will connect- and proxy requests to.
|
4
|
+
|
5
|
+
|
6
|
+
#Make stuff instantly printed to speed up.
|
7
|
+
$stdout.sync = true
|
8
|
+
|
9
|
+
require "rubygems"
|
10
|
+
require "#{File.realpath(File.dirname(__FILE__))}/../lib/hayabusa.rb"
|
11
|
+
require "base64"
|
12
|
+
|
13
|
+
|
14
|
+
#Try to load parent path knjrbfw to allowed developing without updating Gem-installation constantly.
|
15
|
+
begin
|
16
|
+
require "#{File.realpath(File.dirname(__FILE__))}/../../knjrbfw/lib/knjrbfw.rb"
|
17
|
+
rescue LoadError
|
18
|
+
require "knjrbfw"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
#Parse given arguments.
|
23
|
+
opts = {}
|
24
|
+
|
25
|
+
ARGV.each do |val|
|
26
|
+
if match = val.match(/^--(conf_path|fcgi_data_path|title)=(.+)$/)
|
27
|
+
opts[match[1].to_sym] = match[2]
|
28
|
+
else
|
29
|
+
raise "Unknown argument: '#{val}'."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
raise "'conf-path' from arguments could not be found: '#{opts[:conf_path]}'." if !opts[:conf_path] or !File.exists?(opts[:conf_path])
|
34
|
+
require opts[:conf_path]
|
35
|
+
|
36
|
+
|
37
|
+
#Gemerate Hayabusa-config-hash.
|
38
|
+
hayabusa_conf = Hayabusa::FCGI_CONF[:hayabusa]
|
39
|
+
hayabusa_conf.merge!(
|
40
|
+
:debug => false,
|
41
|
+
:debug_log => true,
|
42
|
+
:debug_print => false,
|
43
|
+
:debug_print_err => false,
|
44
|
+
:cmdline => false,
|
45
|
+
:mailing_timeout => 1, #Since FCGI might terminate at any time, try to send out mails almost instantly in the background.
|
46
|
+
:port => 0 #Ruby picks random port and we get the actual port after starting the appserver.
|
47
|
+
)
|
48
|
+
fcgi_server = Hayabusa::Fcgi_server.new(:hayabusa_conf => hayabusa_conf)
|
49
|
+
|
50
|
+
|
51
|
+
#Give information about this process to the FCGI-process that spawned us.
|
52
|
+
puts Base64.strict_encode64(Marshal.dump(
|
53
|
+
:pid => Process.pid,
|
54
|
+
:port => fcgi_server.hayabusa.port
|
55
|
+
))
|
56
|
+
|
57
|
+
|
58
|
+
#Join the server and unlink the config-file when it terminates.
|
59
|
+
begin
|
60
|
+
fcgi_server.hayabusa.join
|
61
|
+
ensure
|
62
|
+
File.unlink(opts[:fcgi_data_path]) if opts[:fcgi_data_path] and File.exists?(opts[:fcgi_data_path])
|
63
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#This script is used to restart the FCGI-spec-test servers.
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "php4r"
|
7
|
+
|
8
|
+
#Close down the running instance of FCGI-server-process.
|
9
|
+
fpath = "/tmp/hayabusa_fcgi_Fcgi_test_fcgi.conf"
|
10
|
+
|
11
|
+
if File.exists?(fpath) and fcont = File.read(fpath) and !fcont.empty?
|
12
|
+
cont = Marshal.load(fcont)
|
13
|
+
Process.kill("HUP", cont[:pid])
|
14
|
+
end
|
15
|
+
|
16
|
+
#Restart apache to restart any FCGI instances.
|
17
|
+
Php4r.passthru("apache2ctl restart")
|
data/hayabusa.gemspec
CHANGED
@@ -5,14 +5,14 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "hayabusa"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.14"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kasper Johansen"]
|
12
|
-
s.date = "2012-09-
|
12
|
+
s.date = "2012-09-30"
|
13
13
|
s.description = "A threadded web/app-server that focuses on threadding, shared ressources, speed and more."
|
14
14
|
s.email = "k@spernj.org"
|
15
|
-
s.executables = ["check_running.rb", "hayabusa_benchmark.rb", "hayabusa_cgi.rb", "hayabusa_fcgi.fcgi", "hayabusa_fcgi.rb", "knjappserver_start.rb"]
|
15
|
+
s.executables = ["check_running.rb", "hayabusa_benchmark.rb", "hayabusa_cgi.rb", "hayabusa_fcgi.fcgi", "hayabusa_fcgi.rb", "hayabusa_fcgi_server.rb", "hayabusa_spec_restart.rb", "knjappserver_start.rb"]
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"LICENSE.txt",
|
18
18
|
"README.rdoc"
|
@@ -31,6 +31,8 @@ Gem::Specification.new do |s|
|
|
31
31
|
"bin/hayabusa_cgi.rb",
|
32
32
|
"bin/hayabusa_fcgi.fcgi",
|
33
33
|
"bin/hayabusa_fcgi.rb",
|
34
|
+
"bin/hayabusa_fcgi_server.rb",
|
35
|
+
"bin/hayabusa_spec_restart.rb",
|
34
36
|
"bin/knjappserver_start.rb",
|
35
37
|
"conf/apache2_cgi_rhtml_conf.conf",
|
36
38
|
"conf/apache2_fcgi_rhtml_conf.conf",
|
@@ -54,6 +56,7 @@ Gem::Specification.new do |s|
|
|
54
56
|
"lib/hayabusa_ext/translations.rb",
|
55
57
|
"lib/hayabusa_ext/web.rb",
|
56
58
|
"lib/hayabusa_fcgi.rb",
|
59
|
+
"lib/hayabusa_fcgi_server.rb",
|
57
60
|
"lib/hayabusa_http_server.rb",
|
58
61
|
"lib/hayabusa_http_session.rb",
|
59
62
|
"lib/hayabusa_http_session_contentgroup.rb",
|
data/lib/hayabusa.rb
CHANGED
@@ -46,8 +46,8 @@ class Hayabusa
|
|
46
46
|
#Require gems.
|
47
47
|
require "rubygems"
|
48
48
|
gems = [
|
49
|
-
[:Erubis, "erubis"],
|
50
49
|
[:Knj, "knjrbfw"],
|
50
|
+
[:Erubis, "erubis"],
|
51
51
|
[:Tsafe, "tsafe"],
|
52
52
|
[:Tpool, "tpool"]
|
53
53
|
]
|
@@ -102,22 +102,20 @@ class Hayabusa
|
|
102
102
|
|
103
103
|
|
104
104
|
@debug = @config[:debug]
|
105
|
-
if @
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
@debug_print_err = true
|
120
|
-
end
|
105
|
+
if !@config.key?(:debug_log) or @config[:debug_log]
|
106
|
+
@debug_log = true
|
107
|
+
else
|
108
|
+
@debug_log = false
|
109
|
+
end
|
110
|
+
|
111
|
+
if @config[:debug_print]
|
112
|
+
@debug_print = true
|
113
|
+
else
|
114
|
+
@debug_print = false
|
115
|
+
end
|
116
|
+
|
117
|
+
if !@config.key?(:debug_print_err) or @config[:debug_print_err]
|
118
|
+
@debug_print_err = true
|
121
119
|
end
|
122
120
|
|
123
121
|
@paused = 0
|
@@ -299,11 +297,10 @@ class Hayabusa
|
|
299
297
|
:name => :request_begin,
|
300
298
|
:connections_max => 1
|
301
299
|
)
|
300
|
+
@events.add_event(:name => :http_session_destruct)
|
302
301
|
|
303
302
|
#This event is used if the user himself wants stuff to be cleaned up when the appserver is cleaning up stuff.
|
304
|
-
@events.add_event(
|
305
|
-
:name => :on_clean
|
306
|
-
)
|
303
|
+
@events.add_event(:name => :on_clean)
|
307
304
|
end
|
308
305
|
|
309
306
|
#Set up the 'vars'-variable that can be used to set custom global variables for web-requests.
|
@@ -345,7 +342,7 @@ class Hayabusa
|
|
345
342
|
end
|
346
343
|
|
347
344
|
|
348
|
-
#Clear memory at exit.
|
345
|
+
#Clear memory, flush emails, flush sessions and more at exit.
|
349
346
|
Kernel.at_exit(&self.method(:stop))
|
350
347
|
|
351
348
|
|
@@ -497,7 +494,7 @@ class Hayabusa
|
|
497
494
|
@httpserv.thread_accept.join
|
498
495
|
@httpserv.thread_restart.join if @httpserv and @httpserv.thread_restart
|
499
496
|
rescue Interrupt => e
|
500
|
-
|
497
|
+
self.log_puts("Trying to stop because of interrupt - please wait while various data is beging flushed.")
|
501
498
|
self.stop
|
502
499
|
end
|
503
500
|
|
data/lib/hayabusa_cgi_tools.rb
CHANGED
@@ -43,11 +43,17 @@ class Hayabusa::Cgi_tools
|
|
43
43
|
|
44
44
|
headers = {"Hayabusa_mode" => "proxy"}
|
45
45
|
cgi.env_table.each do |key, val|
|
46
|
-
|
46
|
+
keyl = key.to_s.downcase
|
47
|
+
|
48
|
+
if key[0, 5] == "HTTP_"
|
47
49
|
key = key[5, key.length].gsub("_", " ")
|
48
50
|
key = key.to_s.split(" ").select{|w| w.capitalize! or w }.join(" ")
|
49
51
|
key = key.gsub(" ", "-")
|
50
|
-
|
52
|
+
keyl = key.downcase
|
53
|
+
|
54
|
+
if keyl != "connection" and keyl != "accept-encoding" and keyl != "hayabusa-fcgi-config" and key != "hayabusa-cgi-config"
|
55
|
+
headers[key] = val
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
@@ -75,6 +75,7 @@ class Hayabusa::Client_session
|
|
75
75
|
|
76
76
|
def execute_page
|
77
77
|
begin
|
78
|
+
@time_start = Time.now.to_f if @debug
|
78
79
|
@hb.events.call(:request_begin, :httpsession => self) if @hb.events
|
79
80
|
|
80
81
|
Timeout.timeout(@hb.config[:timeout]) do
|
@@ -140,7 +141,8 @@ class Hayabusa::Client_session
|
|
140
141
|
def execute_done
|
141
142
|
@cgroup.mark_done
|
142
143
|
@cgroup.write_output
|
143
|
-
@hb.log_puts "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start} secs (#{@resp.status})." if @debug
|
144
|
+
@hb.log_puts "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - @time_start} secs (#{@resp.status})." if @debug
|
145
|
+
@time_start = nil
|
144
146
|
@cgroup.join
|
145
147
|
|
146
148
|
@hb.events.call(:request_done, {
|
data/lib/hayabusa_ext/cleaner.rb
CHANGED
@@ -25,11 +25,11 @@ class Hayabusa
|
|
25
25
|
|
26
26
|
if @config.has_key?(:restart_when_used_memory) and !@should_restart
|
27
27
|
mbs_used = (Php4r.memory_get_usage / 1024) / 1024
|
28
|
-
|
29
|
-
|
28
|
+
self.log_puts("Restart when over #{@config[:restart_when_used_memory]}mb") if @debug
|
29
|
+
self.log_puts("Used: #{mbs_used}mb") if @debug
|
30
30
|
|
31
31
|
if mbs_used.to_i >= @config[:restart_when_used_memory].to_i
|
32
|
-
|
32
|
+
self.log_puts("Memory is over #{@config[:restart_when_used_memory]} - restarting.") if @debug
|
33
33
|
@should_restart = true
|
34
34
|
end
|
35
35
|
end
|
@@ -39,7 +39,7 @@ class Hayabusa
|
|
39
39
|
@should_restart_runnning = true
|
40
40
|
|
41
41
|
#When we begin to restart it should go as fast as possible - so start by flushing out any emails waiting so it goes faster the last time...
|
42
|
-
|
42
|
+
self.log_puts("Flushing mails.") if @debug
|
43
43
|
self.mail_flush
|
44
44
|
|
45
45
|
#Lets try to find a time where no thread is working within the next 30 seconds. If we cant - we interrupt after 10 seconds and restart the server.
|
@@ -51,48 +51,48 @@ class Hayabusa
|
|
51
51
|
|
52
52
|
if working_count and working_count > 0
|
53
53
|
working = true
|
54
|
-
|
54
|
+
self.log_puts("Someone is working - wait two sec and try to restart again!") if @debug
|
55
55
|
end
|
56
56
|
|
57
57
|
if !working
|
58
|
-
|
58
|
+
self.log_puts("Found window where no sessions were active - restarting!") if @debug
|
59
59
|
break
|
60
60
|
else
|
61
61
|
sleep 0.2
|
62
62
|
end
|
63
63
|
|
64
|
-
|
64
|
+
self.log_puts("Trying to find window with no active sessions to restart...") if @debug
|
65
65
|
end
|
66
66
|
end
|
67
67
|
rescue Timeout::Error
|
68
|
-
|
68
|
+
self.log_puts("Could not find a timing window for restarting... Forcing restart!") if @debug
|
69
69
|
end
|
70
70
|
|
71
71
|
#Flush emails again if any are pending (while we tried to find a window to restart)...
|
72
|
-
|
72
|
+
self.log_puts("Flushing mails.") if @debug
|
73
73
|
self.mail_flush
|
74
74
|
|
75
|
-
|
75
|
+
self.log_puts("Stopping appserver.") if @debug
|
76
76
|
self.stop
|
77
77
|
|
78
|
-
|
78
|
+
self.log_puts("Figuring out restart-command.") if @debug
|
79
79
|
mycmd = @config[:restart_cmd]
|
80
80
|
|
81
81
|
if !mycmd or mycmd.to_s.strip.length <= 0
|
82
82
|
fpath = File.realpath("#{File.dirname(__FILE__)}/../hayabusa.rb")
|
83
83
|
mycmd = Knj::Os.executed_cmd
|
84
84
|
|
85
|
-
|
85
|
+
self.log_puts("Previous cmd: #{mycmd}") if @debug
|
86
86
|
mycmd = mycmd.gsub(/\s+hayabusa.rb/, " #{Knj::Strings.unixsafe(fpath)}")
|
87
87
|
end
|
88
88
|
|
89
|
-
|
89
|
+
self.log_puts("Restarting knjAppServer with command: #{mycmd}") if @debug
|
90
90
|
@should_restart_done = true
|
91
91
|
print exec(mycmd)
|
92
92
|
exit
|
93
93
|
rescue => e
|
94
|
-
|
95
|
-
|
94
|
+
self.log_puts(e.inspect)
|
95
|
+
self.log_puts(e.backtrace)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
@@ -103,7 +103,7 @@ class Hayabusa
|
|
103
103
|
|
104
104
|
#This method can be used to clean the appserver. Dont call this from a HTTP-request.
|
105
105
|
def clean_sessions
|
106
|
-
|
106
|
+
self.log_puts("Cleaning sessions on appserver.") if @debug
|
107
107
|
|
108
108
|
#Clean up various inactive sessions.
|
109
109
|
session_not_ids = []
|
@@ -120,10 +120,10 @@ class Hayabusa
|
|
120
120
|
|
121
121
|
@sessions = newsessions
|
122
122
|
|
123
|
-
|
123
|
+
self.log_puts("Delete sessions...") if @debug
|
124
124
|
@ob.list(:Session, {"id_not" => session_not_ids, "date_lastused_below" => (Time.now - 5356800)}) do |session|
|
125
125
|
idhash = session[:idhash]
|
126
|
-
|
126
|
+
self.log_puts("Deleting session: '#{session.id}'.") if @debug
|
127
127
|
@ob.delete(session)
|
128
128
|
@sessions.delete(idhash)
|
129
129
|
end
|
data/lib/hayabusa_ext/errors.rb
CHANGED
@@ -68,7 +68,7 @@ class Hayabusa
|
|
68
68
|
def handle_error(e, args = {})
|
69
69
|
@error_emails_pending_mutex.synchronize do
|
70
70
|
if !Thread.current[:hayabusa] or !Thread.current[:hayabusa][:httpsession]
|
71
|
-
|
71
|
+
self.log_puts("#{Knj::Errors.error_str(e)}\n")
|
72
72
|
end
|
73
73
|
|
74
74
|
browser = _httpsession.browser if _httpsession
|
@@ -122,7 +122,7 @@ class Hayabusa
|
|
122
122
|
|
123
123
|
#Prints a detailed overview of the object in the terminal from where the appserver was started. This can be used for debugging.
|
124
124
|
def dprint(obj)
|
125
|
-
|
125
|
+
self.log_puts(Php4r.print_r(obj, true))
|
126
126
|
end
|
127
127
|
|
128
128
|
#Prints a string with a single file-line-backtrace prepended which is useful for debugging.
|
@@ -130,6 +130,6 @@ class Hayabusa
|
|
130
130
|
#Get backtrace.
|
131
131
|
backtrace_str = caller[0]
|
132
132
|
backtrace_match = backtrace_str.match(/^(.+):(\d+):in /)
|
133
|
-
|
133
|
+
self.log_puts("#{File.basename(backtrace_match[1])}:#{backtrace_match[2]}: #{str}")
|
134
134
|
end
|
135
135
|
end
|
data/lib/hayabusa_ext/logging.rb
CHANGED
@@ -372,7 +372,7 @@ class Hayabusa
|
|
372
372
|
raise "No :ob-argument given." if !args[:ob]
|
373
373
|
|
374
374
|
@db.q_buffer do |db_buffer|
|
375
|
-
|
375
|
+
self.log_puts("Starting to look for dead log-links.") if @debug or args[:debug]
|
376
376
|
@ob.list(:Log_link, :cloned_ubuf => true) do |log_link|
|
377
377
|
classname = log_link.object_class.to_s.split("::").last
|
378
378
|
obj_exists = args[:ob].exists?(classname, log_link[:object_id])
|
@@ -380,23 +380,23 @@ class Hayabusa
|
|
380
380
|
|
381
381
|
log = log_link.log
|
382
382
|
|
383
|
-
|
383
|
+
self.log_puts("Deleting log-link #{log_link.id} for #{classname}(#{log_link[:object_id]}).") if @debug or args[:debug]
|
384
384
|
@ob.delete(log_link, :db_buffer => db_buffer)
|
385
385
|
|
386
386
|
links_count = log.links("count" => true)
|
387
387
|
|
388
388
|
if links_count <= 0
|
389
|
-
|
389
|
+
self.log_puts("Deleting log #{log.id} because it has no more links.") if @debug or args[:debug]
|
390
390
|
@ob.delete(log, :db_buffer => db_buffer)
|
391
391
|
end
|
392
392
|
end
|
393
393
|
|
394
|
-
|
394
|
+
self.log_puts("Starting to look for logs with no links.") if @debug or args[:debug]
|
395
395
|
@ob.list(:Log, {
|
396
396
|
[:Log_link, "id"] => {:type => :sqlval, :val => :null},
|
397
397
|
:cloned_ubuf => true
|
398
398
|
}) do |log|
|
399
|
-
|
399
|
+
self.log_puts("Deleting log #{log.id} because it has no links: '#{log.text}'.") if @debug or args[:debug]
|
400
400
|
@ob.delete(log, :db_buffer => db_buffer)
|
401
401
|
end
|
402
402
|
end
|
data/lib/hayabusa_ext/mailing.rb
CHANGED
@@ -28,7 +28,7 @@ class Hayabusa
|
|
28
28
|
end
|
29
29
|
|
30
30
|
mailobj = Hayabusa::Mail.new({:hb => self, :errors => {}, :status => :waiting}.merge(mail_args))
|
31
|
-
|
31
|
+
self.log_puts("Added mail '#{mailobj.__id__}' to the mail-send-queue.") if debug
|
32
32
|
@mails_waiting << mailobj
|
33
33
|
|
34
34
|
#Try to send right away and raise error instantly if something happens if told to do so.
|
@@ -44,34 +44,34 @@ class Hayabusa
|
|
44
44
|
#Sends all queued mails to the respective servers, if we are online.
|
45
45
|
def mail_flush
|
46
46
|
@mails_mutex.synchronize do
|
47
|
-
|
47
|
+
self.log_puts("Flushing mails.") if @debug
|
48
48
|
|
49
49
|
if @mails_waiting.length <= 0
|
50
|
-
|
50
|
+
self.log_puts("No mails to flush - skipping.") if @debug
|
51
51
|
return false
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
self.log_puts("Trying to ping Google to figure out if we are online...") if @debug
|
55
55
|
status = Ping.pingecho("google.dk", 10, 80)
|
56
56
|
if !status
|
57
|
-
|
57
|
+
self.log_puts("We are not online - skipping mail flush.")
|
58
58
|
return false #Dont run if we dont have a connection to the internet and then properly dont have a connection to the SMTP as well.
|
59
59
|
end
|
60
60
|
|
61
61
|
#Use subprocessing to avoid the mail-framework (activesupport and so on, also possible memory leaks in those large frameworks).
|
62
|
-
|
62
|
+
self.log_puts("Starting subprocess for mailing.") if @debug
|
63
63
|
Knj::Process_meta.new("debug" => @debug, "debug_err" => true, "id" => "hayabusa_mailing") do |subproc|
|
64
64
|
subproc.static("Object", "require", "rubygems")
|
65
65
|
subproc.static("Object", "require", "mail")
|
66
66
|
subproc.static("Object", "require", "#{@config[:knjrbfw_path]}knjrbfw")
|
67
67
|
subproc.static("Object", "require", "knj/autoload")
|
68
68
|
|
69
|
-
|
69
|
+
self.log_puts("Flushing emails.") if @debug
|
70
70
|
@mails_waiting.each do |mail|
|
71
71
|
begin
|
72
|
-
|
72
|
+
self.log_puts("Sending email: #{mail.__id__}") if @debug
|
73
73
|
if mail.send("proc" => subproc)
|
74
|
-
|
74
|
+
self.log_puts("Email sent: #{mail.__id__}") if @debug
|
75
75
|
@mails_waiting.delete(mail)
|
76
76
|
end
|
77
77
|
rescue Timeout::Error
|
@@ -117,7 +117,7 @@ class Hayabusa
|
|
117
117
|
|
118
118
|
#Sends the email to the receiver.
|
119
119
|
def send(args = {})
|
120
|
-
|
120
|
+
@args[:hb].log_puts("Sending mail '#{__id__}'.") if @args[:hb].debug
|
121
121
|
|
122
122
|
if args["proc"]
|
123
123
|
args["proc"].static("Object", "require", "knj/mailobj")
|
@@ -139,13 +139,13 @@ class Hayabusa
|
|
139
139
|
end
|
140
140
|
|
141
141
|
@args[:status] = :sent
|
142
|
-
|
142
|
+
@args[:hb].log_puts("Sent email #{self.__id__}") if @args[:hb].debug
|
143
143
|
return true
|
144
144
|
rescue => e
|
145
145
|
if @args[:hb].debug
|
146
|
-
|
147
|
-
|
148
|
-
|
146
|
+
@args[:hb].log_puts("Could not send email.")
|
147
|
+
@args[:hb].log_puts(e.inspect)
|
148
|
+
@args[:hb].log_puts(e.backtrace)
|
149
149
|
end
|
150
150
|
|
151
151
|
@args[:errors][e.class.name] = {:count => 0} if !@args[:errors].has_key?(e.class.name)
|
@@ -73,7 +73,7 @@ class Hayabusa
|
|
73
73
|
def sessions_flush
|
74
74
|
if @sessions
|
75
75
|
@sessions.each do |session_hash, session_data|
|
76
|
-
|
76
|
+
self.log_puts("Flushing session: #{session_data[:dbobj].id}") if @debug
|
77
77
|
session_data[:dbobj].flush
|
78
78
|
end
|
79
79
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Hayabusa
|
2
2
|
def initialize_threadding
|
3
3
|
@config[:threadding] = {} if !@config.has_key?(:threadding)
|
4
|
-
@config[:threadding][:max_running] =
|
4
|
+
@config[:threadding][:max_running] = 16 if !@config[:threadding].has_key?(:max_running)
|
5
5
|
|
6
6
|
threadpool_args = {:threads => @config[:threadding][:max_running]}
|
7
7
|
threadpool_args[:priority] = @config[:threadding][:priority] if @config[:threadding].key?(:priority)
|
@@ -30,35 +30,38 @@ class Hayabusa
|
|
30
30
|
thread_obj = Hayabusa::Thread_instance.new(
|
31
31
|
:running => false,
|
32
32
|
:error => false,
|
33
|
-
:done => false
|
33
|
+
:done => false,
|
34
|
+
:args => args
|
34
35
|
)
|
35
36
|
|
36
37
|
@threadpool.run_async do
|
37
|
-
@ob.db.get_and_register_thread if @ob.db.opts[:threadsafe]
|
38
|
-
@db_handler.get_and_register_thread if @db_handler.opts[:threadsafe]
|
39
|
-
|
40
|
-
Thread.current[:hayabusa] = {
|
41
|
-
:hb => self,
|
42
|
-
:db => @db_handler
|
43
|
-
}
|
44
|
-
|
45
38
|
begin
|
39
|
+
@ob.db.get_and_register_thread if @ob.db.opts[:threadsafe]
|
40
|
+
@db_handler.get_and_register_thread if @db_handler.opts[:threadsafe]
|
41
|
+
|
42
|
+
Thread.current[:hayabusa] = {
|
43
|
+
:hb => self,
|
44
|
+
:db => @db_handler
|
45
|
+
}
|
46
|
+
|
46
47
|
thread_obj.args[:running] = true
|
47
48
|
yield(*args[:args])
|
49
|
+
_hb.log_puts("Done yielding for #{args[:id]}")
|
48
50
|
rescue => e
|
49
|
-
self.handle_error(e)
|
50
51
|
thread_obj.args[:error] = true
|
51
52
|
thread_obj.args[:error_obj] = e
|
53
|
+
|
54
|
+
self.handle_error(e)
|
52
55
|
ensure
|
53
|
-
|
56
|
+
_hb.log_puts("Seting arguments on thread.") if @debug
|
57
|
+
thread_obj.args[:running] = false
|
58
|
+
thread_obj.args[:done] = true
|
59
|
+
|
60
|
+
_hb.log_puts("Free thread ob-db.") if @debug
|
54
61
|
@ob.db.free_thread if @ob.db.opts[:threadsafe]
|
55
62
|
|
56
|
-
|
63
|
+
_hb.log_puts("Free thread db-handler.") if @debug
|
57
64
|
@db_handler.free_thread if @db_handler.opts[:threadsafe]
|
58
|
-
|
59
|
-
STDOUT.print "Seting arguments on thread.\n" if @debug
|
60
|
-
thread_obj.args[:running] = false
|
61
|
-
thread_obj.args[:done] = true
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
@@ -105,8 +108,24 @@ class Hayabusa::Thread_instance
|
|
105
108
|
@args = args
|
106
109
|
end
|
107
110
|
|
111
|
+
def running?
|
112
|
+
return @args[:running]
|
113
|
+
end
|
114
|
+
|
115
|
+
def done?
|
116
|
+
return @args[:done]
|
117
|
+
end
|
118
|
+
|
119
|
+
def error?
|
120
|
+
return true if @args[:error]
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
|
108
124
|
def join
|
109
|
-
|
125
|
+
while !@args[:done] and !@args[:error]
|
126
|
+
_hb.log_puts(@args)
|
127
|
+
sleep 0.1
|
128
|
+
end
|
110
129
|
end
|
111
130
|
|
112
131
|
def join_error
|
data/lib/hayabusa_fcgi.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#This class is used for FCGI-sessions. It normally starts a Hayabusa-host-process which this (and other) FCGI-processes will proxy requests to. The host-process will automatically kill itself when no more FCGI-sessions are connected to emulate normal FCGI behaviour.
|
1
2
|
class Hayabusa::Fcgi
|
2
3
|
def initialize
|
3
4
|
#Spawn CGI-variable to emulate FCGI part.
|
@@ -10,6 +11,7 @@ class Hayabusa::Fcgi
|
|
10
11
|
@debug = false
|
11
12
|
end
|
12
13
|
|
14
|
+
#Evaluates if a new host-process should be started or we should proxy calls to an existing one.
|
13
15
|
def evaluate_mode
|
14
16
|
#If this is a FCGI-proxy-instance then the HTTP-connection should be checked if it is working.
|
15
17
|
if @fcgi_proxy
|
@@ -52,7 +54,7 @@ class Hayabusa::Fcgi
|
|
52
54
|
#Set this instance to run in proxy-mode.
|
53
55
|
begin
|
54
56
|
@fcgi_proxy = fcgi_config
|
55
|
-
Knj.gem_require(:Http2
|
57
|
+
Knj.gem_require(:Http2)
|
56
58
|
|
57
59
|
begin
|
58
60
|
@fcgi_proxy[:http] = Http2.new(:host => "localhost", :port => @fcgi_proxy[:port].to_i)
|
@@ -74,21 +76,46 @@ class Hayabusa::Fcgi
|
|
74
76
|
|
75
77
|
#No instance is already running - start new Hayabusa-instance in both CGI- and socket-mode and write that to the config-file so other instances will register this as the main host-instance.
|
76
78
|
if !@fcgi_proxy
|
79
|
+
#Spawn sub-process that actually runs the Hayabusa-server.
|
80
|
+
require "open3"
|
81
|
+
cmd = "#{Knj::Os.executed_executable} #{File.realpath(File.dirname(__FILE__))}/../bin/hayabusa_fcgi_server.rb --conf_path=#{Knj::Strings.unixsafe(@hayabusa_fcgi_conf_path)} --fcgi_data_path=#{Knj::Strings.unixsafe(fcgi_config_fp)}"
|
82
|
+
|
83
|
+
#Only used to identify the running FCGI-server host-processes with 'ps aux'.
|
84
|
+
cmd << "--title=#{Knj::Strings.unixsafe(hayabusa_conf[:title])}" if hayabusa_conf[:title]
|
85
|
+
|
86
|
+
$stderr.puts("Executing command to start FCGI-server: #{cmd}")
|
87
|
+
io_out, io_in, io_err = Open3.popen3(cmd)
|
88
|
+
|
89
|
+
#Get data that should contain PID and port.
|
90
|
+
read = io_in.gets
|
91
|
+
raise "Host-process didnt return required data." if !read
|
92
|
+
|
93
|
+
#Parse data from the host-process (port and PID).
|
94
|
+
begin
|
95
|
+
data = Marshal.load(Base64.strict_decode64(read.strip))
|
96
|
+
rescue
|
97
|
+
raise "Invalid data given from host-process: '#{read}'."
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
#Detach the process where the HTTP-server runs from this process.
|
102
|
+
Process.detach(data[:pid])
|
103
|
+
|
104
|
+
#Write the data about the new HTTP-server in the config-file and re-evaluate mode. The host-process should not write the file itself, since this process has a lock on that file, and another process might try to start another host-process while writing the file from the host-process, which is not desired.
|
77
105
|
File.open(fcgi_config_fp, "w") do |fp|
|
78
|
-
@hayabusa = Hayabusa.new(hayabusa_conf)
|
79
|
-
|
80
|
-
#Start web-server for proxy-requests.
|
81
|
-
@hayabusa.start
|
82
|
-
|
83
106
|
fp.write(Marshal.dump(
|
84
|
-
:pid =>
|
85
|
-
:port =>
|
107
|
+
:pid => data[:pid],
|
108
|
+
:port => data[:port]
|
86
109
|
))
|
110
|
+
|
111
|
+
#Started host-process - evaluate mode again and proxy request to the host-process.
|
112
|
+
raise Errno::EAGAIN
|
87
113
|
end
|
88
114
|
end
|
89
115
|
end
|
90
116
|
end
|
91
117
|
|
118
|
+
#Handels the requests comming from the FCGI-object in a loop.
|
92
119
|
def fcgi_loop
|
93
120
|
$stderr.puts "[hayabusa] Starting FCGI." if @debug
|
94
121
|
|
@@ -119,8 +146,8 @@ class Hayabusa::Fcgi
|
|
119
146
|
else
|
120
147
|
self.handle_fcgi_request(:cgi => cgi)
|
121
148
|
end
|
122
|
-
rescue Errno::ECONNABORTED, Errno::ECONNREFUSED
|
123
|
-
$stderr.puts "[hayabusa] Connection to server was interrupted - trying again."
|
149
|
+
rescue Errno::ECONNABORTED, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
150
|
+
$stderr.puts "[hayabusa] Connection to server was interrupted - trying again: <#{e.class.name}> #{e.message}"
|
124
151
|
@fcgi_proxy = nil #Force re-evaluate if this process should be host or proxy.
|
125
152
|
retry
|
126
153
|
rescue Exception => e
|
@@ -146,6 +173,7 @@ class Hayabusa::Fcgi
|
|
146
173
|
end
|
147
174
|
end
|
148
175
|
|
176
|
+
#Handles the request as a real request on a Hayabusa-host running inside the current process. This is not used any more but kept if we need support for it once again (maybe the developer should be able to decide this in some kind of config?).
|
149
177
|
def handle_fcgi_request(args)
|
150
178
|
#Host the FCGI-process.
|
151
179
|
$stderr.puts "[hayabusa] Running request as CGI." if @debug
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#This class is used to start Hayabusa in its own process, which FCGI-sessions then connects to. This way only one instance of Hayabusa is actually running to allowed FCGI-sessions to "commuicate" with each other (because they are running in the same process).
|
2
|
+
class Hayabusa::Fcgi_server
|
3
|
+
attr_reader :hayabusa
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
#Start web-server for proxy-requests.
|
7
|
+
@hayabusa = Hayabusa.new(args[:hayabusa_conf])
|
8
|
+
@hayabusa.start
|
9
|
+
|
10
|
+
#In FCGI-mode the host-process should exit when zero FCGI-connections are active.
|
11
|
+
@hayabusa.events.connect(:http_session_destruct, &self.method(:on_http_session_destruct))
|
12
|
+
end
|
13
|
+
|
14
|
+
#Called when a HTTP-session destructs (disconnects). Used to stop the Hayabusa-appserver when no connections are active to only be running when FCGI-sessions are running.
|
15
|
+
def on_http_session_destruct(*args)
|
16
|
+
@hayabusa.log_puts("HTTP-connection destruction - checking if no connections are active any more.")
|
17
|
+
|
18
|
+
stop = false
|
19
|
+
httpserv = @hayabusa.httpserv
|
20
|
+
|
21
|
+
if !httpserv or !httpserv.http_sessions or httpserv.http_sessions.empty?
|
22
|
+
stop = true
|
23
|
+
end
|
24
|
+
|
25
|
+
if stop
|
26
|
+
@hayabusa.log_puts("Stopping server because no active connections.")
|
27
|
+
@hayabusa.stop
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/hayabusa_http_server.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "socket"
|
2
2
|
|
3
|
+
#This class opens a port to run the HTTP-server on. It then spawns "Hayabusa::Http_session" for each active connection.
|
3
4
|
class Hayabusa::Http_server
|
4
5
|
attr_accessor :working_count
|
5
6
|
attr_reader :hb, :http_sessions, :thread_accept, :thread_restart, :server
|
@@ -10,6 +11,7 @@ class Hayabusa::Http_server
|
|
10
11
|
@mutex_count = Mutex.new
|
11
12
|
end
|
12
13
|
|
14
|
+
#Opens a port with TCPServer and spins up a thread to accept connections.
|
13
15
|
def start
|
14
16
|
@http_sessions = []
|
15
17
|
@working_count = 0
|
@@ -43,6 +45,7 @@ class Hayabusa::Http_server
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
48
|
+
#Gently stops the HTTP-server. Will wait for various HTTP-sessions to be finish with a page (but wont wait for them to disconnect in regards to keep-alive).
|
46
49
|
def stop
|
47
50
|
while @working_count > 0
|
48
51
|
@hb.log_puts "Waiting until no HTTP-sessions are running." if @debug
|
@@ -83,11 +86,13 @@ class Hayabusa::Http_server
|
|
83
86
|
@hb = nil
|
84
87
|
end
|
85
88
|
|
89
|
+
#Spawns a new HTTP-session with the given socket.
|
86
90
|
def spawn_httpsession(socket)
|
87
|
-
@hb.log_puts
|
91
|
+
@hb.log_puts("Starting new HTTP-session.") if @debug
|
88
92
|
@http_sessions << Hayabusa::Http_session.new(self, socket)
|
89
93
|
end
|
90
94
|
|
95
|
+
#Increases and decreases the 'working_count'-variable to keep track of how many HTTP-sessions are currently processing pages (used for gentle stops).
|
91
96
|
def count_block
|
92
97
|
begin
|
93
98
|
added = false
|
@@ -141,14 +141,14 @@ class Hayabusa::Http_session < Hayabusa::Client_session
|
|
141
141
|
begin
|
142
142
|
@socket.close if !@socket.closed?
|
143
143
|
rescue => e
|
144
|
-
|
145
|
-
|
144
|
+
@hb.log_puts(e.inspect)
|
145
|
+
@hb.log_puts(e.backtrace)
|
146
146
|
#ignore if it fails...
|
147
147
|
end
|
148
148
|
|
149
149
|
@httpserver.http_sessions.delete(self) if @httpserver and @httpserver.http_sessions
|
150
|
-
|
151
150
|
@eruby.destroy if @eruby
|
151
|
+
@hb.events.call(:http_session_destruct, :httpsession => self) if @hb.events
|
152
152
|
@thread_request.kill if @thread_request.alive?
|
153
153
|
end
|
154
154
|
|
@@ -208,7 +208,7 @@ class Hayabusa::Http_session < Hayabusa::Client_session
|
|
208
208
|
"name" => "HayabusaSession",
|
209
209
|
"value" => @session_id,
|
210
210
|
"path" => "/",
|
211
|
-
"expires" => Time.now + 32140800 #add around 12 months
|
211
|
+
"expires" => Time.now + 32140800 #add around 12 months from the current time
|
212
212
|
)
|
213
213
|
end
|
214
214
|
|
@@ -230,7 +230,6 @@ class Hayabusa::Http_session < Hayabusa::Client_session
|
|
230
230
|
@hb.log_puts "Initializing thread and content-group." if @debug
|
231
231
|
self.init_thread
|
232
232
|
Thread.current[:hayabusa][:contentgroup] = @cgroup
|
233
|
-
time_start = Time.now.to_f if @debug
|
234
233
|
|
235
234
|
self.execute_page
|
236
235
|
self.execute_done
|
@@ -1,20 +1,35 @@
|
|
1
1
|
<%
|
2
|
+
#Knj.p _hb.config
|
3
|
+
#exit
|
4
|
+
|
5
|
+
_hb.log_puts("1")
|
2
6
|
print "1"
|
3
7
|
|
8
|
+
_hb.log_puts("2")
|
4
9
|
cont = "2"
|
5
|
-
t1 = _hb.thread do
|
10
|
+
t1 = _hb.thread(:id => 4) do
|
6
11
|
sleep 0.5
|
12
|
+
_hb.log_puts("4")
|
7
13
|
cont << "4"
|
14
|
+
_hb.log_puts("4 done")
|
8
15
|
end
|
9
16
|
|
10
|
-
t2 = _hb.thread do
|
11
|
-
sleep 0.
|
17
|
+
t2 = _hb.thread(:id => 3) do
|
18
|
+
sleep 0.3
|
19
|
+
_hb.log_puts("3")
|
12
20
|
cont << "3"
|
21
|
+
_hb.log_puts("3 done")
|
13
22
|
end
|
14
23
|
|
24
|
+
sleep 0.1
|
25
|
+
|
26
|
+
raise "Expected thread 1 to be running but it wasnt." if !t1.running?
|
27
|
+
raise "Expected thread 2 to be running but it wasnt." if !t2.running?
|
28
|
+
|
15
29
|
t1.join
|
16
30
|
t2.join_error
|
17
31
|
|
32
|
+
_hb.log_puts("5")
|
18
33
|
cont << "5"
|
19
34
|
|
20
35
|
print cont
|
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
describe "Hayabusa" do
|
4
4
|
it "should handle sessions correctly under stressed conditions" do
|
5
5
|
require "knjrbfw"
|
6
|
-
Knj.gem_require(:Http2
|
6
|
+
Knj.gem_require(:Http2)
|
7
7
|
require "json"
|
8
8
|
|
9
9
|
ts = []
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: hayabusa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.14
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kasper Johansen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-09-
|
13
|
+
date: 2012-09-30 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: knjrbfw
|
@@ -141,6 +141,8 @@ executables:
|
|
141
141
|
- hayabusa_cgi.rb
|
142
142
|
- hayabusa_fcgi.fcgi
|
143
143
|
- hayabusa_fcgi.rb
|
144
|
+
- hayabusa_fcgi_server.rb
|
145
|
+
- hayabusa_spec_restart.rb
|
144
146
|
- knjappserver_start.rb
|
145
147
|
extensions: []
|
146
148
|
|
@@ -161,6 +163,8 @@ files:
|
|
161
163
|
- bin/hayabusa_cgi.rb
|
162
164
|
- bin/hayabusa_fcgi.fcgi
|
163
165
|
- bin/hayabusa_fcgi.rb
|
166
|
+
- bin/hayabusa_fcgi_server.rb
|
167
|
+
- bin/hayabusa_spec_restart.rb
|
164
168
|
- bin/knjappserver_start.rb
|
165
169
|
- conf/apache2_cgi_rhtml_conf.conf
|
166
170
|
- conf/apache2_fcgi_rhtml_conf.conf
|
@@ -184,6 +188,7 @@ files:
|
|
184
188
|
- lib/hayabusa_ext/translations.rb
|
185
189
|
- lib/hayabusa_ext/web.rb
|
186
190
|
- lib/hayabusa_fcgi.rb
|
191
|
+
- lib/hayabusa_fcgi_server.rb
|
187
192
|
- lib/hayabusa_http_server.rb
|
188
193
|
- lib/hayabusa_http_session.rb
|
189
194
|
- lib/hayabusa_http_session_contentgroup.rb
|
@@ -240,7 +245,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
240
245
|
requirements:
|
241
246
|
- - ">="
|
242
247
|
- !ruby/object:Gem::Version
|
243
|
-
hash:
|
248
|
+
hash: 888767182680774997
|
244
249
|
segments:
|
245
250
|
- 0
|
246
251
|
version: "0"
|