nezu 0.4.13
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +13 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +77 -0
- data/README.md +14 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/nezu +8 -0
- data/lib/nezu/cli.rb +43 -0
- data/lib/nezu/generators/application/MANIFEST +16 -0
- data/lib/nezu/generators/application/USAGE +15 -0
- data/lib/nezu/generators/application/app_generator.rb +37 -0
- data/lib/nezu/generators/application/templates/.gitignore +15 -0
- data/lib/nezu/generators/application/templates/Gemfile +9 -0
- data/lib/nezu/generators/application/templates/README.md +0 -0
- data/lib/nezu/generators/application/templates/Rakefile +7 -0
- data/lib/nezu/generators/application/templates/app/consumers/$app_name.rb.tt +4 -0
- data/lib/nezu/generators/application/templates/app/consumers/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/app/models/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/app/producers/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/config/amqp.yml.tt +9 -0
- data/lib/nezu/generators/application/templates/config/boot.rb.tt +6 -0
- data/lib/nezu/generators/application/templates/config/database.yml.tt +9 -0
- data/lib/nezu/generators/application/templates/config/initializers/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/config/nezu.rb.tt +11 -0
- data/lib/nezu/generators/application/templates/db/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/log/.gitkeep +0 -0
- data/lib/nezu/generators/application/templates/spec/.gitkeep +0 -0
- data/lib/nezu/generators.rb +45 -0
- data/lib/nezu/runner.rb +87 -0
- data/lib/nezu/runtime/consumer.rb +35 -0
- data/lib/nezu/runtime/producer.rb +28 -0
- data/lib/nezu/runtime/recipient.rb +24 -0
- data/lib/nezu/runtime/worker.rb +24 -0
- data/lib/nezu.rb +34 -0
- data/nezu.gemspec +25 -0
- data/spec/functional/generators/app_generator_spec.rb +52 -0
- data/spec/functional/generators_spec.rb +36 -0
- data/spec/functional/nezu_spec.rb +11 -0
- data/spec/functional/runner_spec.rb +0 -0
- data/spec/functional/runtime/consumer_spec.rb +54 -0
- data/spec/functional/runtime/producer_spec.rb +24 -0
- data/spec/functional/runtime/recipient_spec.rb +15 -0
- data/spec/integration/user_script_spec.rb +6 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/lib/nezu/generators/application/templates/test_file.tt +2 -0
- data/spec/support/lib/nezu/generators/application/templates/test_file_without_suffix +0 -0
- data/spec/support/sample_project/.gitignore +15 -0
- data/spec/support/sample_project/Gemfile +9 -0
- data/spec/support/sample_project/README.md +0 -0
- data/spec/support/sample_project/Rakefile +7 -0
- data/spec/support/sample_project/app/consumers/.gitkeep +0 -0
- data/spec/support/sample_project/app/consumers/sample_project.rb +4 -0
- data/spec/support/sample_project/app/models/.gitkeep +0 -0
- data/spec/support/sample_project/app/producers/.gitkeep +0 -0
- data/spec/support/sample_project/config/amqp.yml +9 -0
- data/spec/support/sample_project/config/boot.rb +6 -0
- data/spec/support/sample_project/config/database.yml +9 -0
- data/spec/support/sample_project/config/initializers/.gitkeep +0 -0
- data/spec/support/sample_project/config/nezu.rb +11 -0
- data/spec/support/sample_project/db/.gitkeep +0 -0
- data/spec/support/sample_project/spec/.gitkeep +0 -0
- data/spec/support/tmp/.gitkeep +0 -0
- metadata +252 -0
data/.document
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nezu (0.4.11)
|
5
|
+
activerecord (~> 3.2.11)
|
6
|
+
activesupport (~> 3.2.11)
|
7
|
+
amqp
|
8
|
+
bunny (>= 0.9.0.pre6)
|
9
|
+
configatron
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
activemodel (3.2.12)
|
15
|
+
activesupport (= 3.2.12)
|
16
|
+
builder (~> 3.0.0)
|
17
|
+
activerecord (3.2.12)
|
18
|
+
activemodel (= 3.2.12)
|
19
|
+
activesupport (= 3.2.12)
|
20
|
+
arel (~> 3.0.2)
|
21
|
+
tzinfo (~> 0.3.29)
|
22
|
+
activesupport (3.2.12)
|
23
|
+
i18n (~> 0.6)
|
24
|
+
multi_json (~> 1.0)
|
25
|
+
amq-client (0.9.12)
|
26
|
+
amq-protocol (>= 1.2.0)
|
27
|
+
eventmachine
|
28
|
+
amq-protocol (1.2.0)
|
29
|
+
amqp (0.9.9)
|
30
|
+
amq-client (~> 0.9.12)
|
31
|
+
amq-protocol (~> 1.2.0)
|
32
|
+
eventmachine
|
33
|
+
arel (3.0.2)
|
34
|
+
builder (3.0.4)
|
35
|
+
bunny (0.9.0.pre7)
|
36
|
+
amq-protocol (>= 1.2.0)
|
37
|
+
columnize (0.3.6)
|
38
|
+
configatron (2.10.0)
|
39
|
+
yamler (>= 0.1.0)
|
40
|
+
debugger (1.3.3)
|
41
|
+
columnize (>= 0.3.1)
|
42
|
+
debugger-linecache (~> 1.1.1)
|
43
|
+
debugger-ruby_core_source (~> 1.2.0)
|
44
|
+
debugger-linecache (1.1.2)
|
45
|
+
debugger-ruby_core_source (>= 1.1.1)
|
46
|
+
debugger-ruby_core_source (1.2.0)
|
47
|
+
diff-lcs (1.2.1)
|
48
|
+
eventmachine (1.0.1)
|
49
|
+
i18n (0.6.4)
|
50
|
+
json (1.7.7)
|
51
|
+
multi_json (1.6.1)
|
52
|
+
rake (10.0.3)
|
53
|
+
rdoc (3.12.2)
|
54
|
+
json (~> 1.4)
|
55
|
+
rspec (2.13.0)
|
56
|
+
rspec-core (~> 2.13.0)
|
57
|
+
rspec-expectations (~> 2.13.0)
|
58
|
+
rspec-mocks (~> 2.13.0)
|
59
|
+
rspec-core (2.13.0)
|
60
|
+
rspec-expectations (2.13.0)
|
61
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
62
|
+
rspec-mocks (2.13.0)
|
63
|
+
sdoc (0.3.20)
|
64
|
+
json (>= 1.1.3)
|
65
|
+
rdoc (~> 3.10)
|
66
|
+
tzinfo (0.3.36)
|
67
|
+
yamler (0.1.0)
|
68
|
+
|
69
|
+
PLATFORMS
|
70
|
+
ruby
|
71
|
+
|
72
|
+
DEPENDENCIES
|
73
|
+
debugger
|
74
|
+
nezu!
|
75
|
+
rake
|
76
|
+
rspec
|
77
|
+
sdoc
|
data/README.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Nezu
|
2
|
+
====
|
3
|
+
Nezu is a rails inspired simple amqp app framework. Right now it is pretty much a work in progress though we hope that it will do the job here at talkyoo.net.
|
4
|
+
It has two major modes of usage:
|
5
|
+
|
6
|
+
1. nezu new /path/to/your/app
|
7
|
+
generates an app-skeleton
|
8
|
+
|
9
|
+
2. (bundle exec) nezu run
|
10
|
+
inside your app folder starts your application and subscribes all your consumers to their appropriate queues
|
11
|
+
|
12
|
+
*BIGFATALPHAWARNING:*
|
13
|
+
This hasn`t been fully tested yet. So if your working on a nuclear plant or so, go back to sleep this will be a lower risk
|
14
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rdoc/task'
|
6
|
+
require 'sdoc'
|
7
|
+
require 'debugger'
|
8
|
+
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
12
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::RDocTask.new do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
17
|
+
rdoc.options << '--fmt' << 'shtml'
|
18
|
+
rdoc.template = 'direct'
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :version do
|
22
|
+
namespace :bump do
|
23
|
+
desc 'Increase the major number and set the others to zero'
|
24
|
+
task :major do
|
25
|
+
major, minor, patch = load_version
|
26
|
+
store_version(major + 1, 0, 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'Increase the minor number and set patch to zero'
|
30
|
+
task :minor do
|
31
|
+
major, minor, patch = load_version
|
32
|
+
store_version(major, minor + 1, 0)
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Increase the patch level'
|
36
|
+
task :patch do
|
37
|
+
major, minor, patch = load_version
|
38
|
+
store_version(major, minor, patch + 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_version
|
42
|
+
File.read(File.join(File.dirname(__FILE__), 'VERSION')).split('.').map(&:to_i)
|
43
|
+
end
|
44
|
+
|
45
|
+
def store_version(major, minor, patch)
|
46
|
+
version = "#{major}.#{minor}.#{patch}"
|
47
|
+
f= File.new(File.join(File.dirname(__FILE__), 'VERSION'), File::WRONLY)
|
48
|
+
f.write(version)
|
49
|
+
f.close
|
50
|
+
puts "version is now #{version}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.13
|
data/bin/nezu
ADDED
data/lib/nezu/cli.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
Signal.trap("INT") { puts; exit(1) }
|
2
|
+
|
3
|
+
module Nezu
|
4
|
+
module CLI
|
5
|
+
def self.help(*params)
|
6
|
+
script_name = File.basename(__FILE__)
|
7
|
+
puts %Q(
|
8
|
+
Usage:
|
9
|
+
|
10
|
+
"#{script_name} new <appname>" for an app skeleton dir in <appname>
|
11
|
+
"#{script_name} run" inside an app dir to start it
|
12
|
+
|
13
|
+
).gsub(/^\s*/, '')
|
14
|
+
exit(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.new(*params)
|
18
|
+
amqp_scope = params[0].grep(/--amqp_scope/)[0].match(/=(\S*)/)[1] rescue nil
|
19
|
+
configatron.amqp_scope = amqp_scope if amqp_scope
|
20
|
+
puts %Q(Creating application dir in "#{params[0][0]}")
|
21
|
+
require 'nezu/generators'
|
22
|
+
app = Nezu::Generators::Application::AppGenerator.new(params[0][0])
|
23
|
+
app.generate!
|
24
|
+
puts %Q(Successfully created App.)
|
25
|
+
exit(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run(*params)
|
29
|
+
puts %Q(Starting app...)
|
30
|
+
require 'nezu/runner'
|
31
|
+
Nezu::Runner.new
|
32
|
+
exit(0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
Nezu::CLI.send(ARGV.shift, ARGV)
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.gitignore
|
2
|
+
Gemfile
|
3
|
+
README.md
|
4
|
+
Rakefile
|
5
|
+
app/consumers/$app_name.rb.tt
|
6
|
+
app/consumers/.gitkeep
|
7
|
+
app/models/.gitkeep
|
8
|
+
app/producers/.gitkeep
|
9
|
+
config/amqp.yml.tt
|
10
|
+
config/boot.rb.tt
|
11
|
+
config/database.yml.tt
|
12
|
+
config/initializers/.gitkeep
|
13
|
+
config/nezu.rb.tt
|
14
|
+
db/.gitkeep
|
15
|
+
log/.gitkeep
|
16
|
+
spec/.gitkeep
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Description:
|
2
|
+
The 'rails new' command creates a new Rails application with a default
|
3
|
+
directory structure and configuration at the path you specify.
|
4
|
+
|
5
|
+
You can specify extra command-line arguments to be used every time
|
6
|
+
'rails new' runs in the .railsrc configuration file in your home directory.
|
7
|
+
|
8
|
+
Note that the arguments specified in the .railsrc file don't affect the
|
9
|
+
defaults values shown above in this help message.
|
10
|
+
|
11
|
+
Example:
|
12
|
+
rails new ~/Code/Ruby/weblog
|
13
|
+
|
14
|
+
This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
|
15
|
+
See the README in the newly created application to get going.
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Nezu
|
2
|
+
module Generators
|
3
|
+
module Application
|
4
|
+
class AppGenerator
|
5
|
+
include Nezu::Generators
|
6
|
+
|
7
|
+
def initialize(destination_root)
|
8
|
+
configatron.destination_root = destination_root
|
9
|
+
configatron.app_name = File.basename(destination_root)
|
10
|
+
name_space = configatron.app_name.split(/_/).map(&:capitalize).join('').to_sym
|
11
|
+
configatron.name_space = Object.const_set(name_space, Module.new) unless Object.const_defined?(name_space)
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate!
|
15
|
+
raise Nezu::Generators::Application::AppGeneratorError, "\"#{configatron.destination_root}\" already exists" if Dir.exist?(configatron.destination_root)
|
16
|
+
FileUtils.mkdir_p(configatron.destination_root)
|
17
|
+
generate_files_from_manifest!
|
18
|
+
rename_app_name_template
|
19
|
+
end
|
20
|
+
|
21
|
+
def rename_app_name_template
|
22
|
+
File.rename(File.join(configatron.destination_root,'app/consumers/$app_name.rb'),
|
23
|
+
File.join(configatron.destination_root,"app/consumers/#{configatron.app_name}.rb"))
|
24
|
+
end
|
25
|
+
|
26
|
+
def generate_files_from_manifest! # TODO rewrite so a MANIFEST isn´t needed
|
27
|
+
File.readlines(File.join(File.dirname(__FILE__), 'MANIFEST')).each do |filename|
|
28
|
+
template_to(filename.chomp)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
class AppGeneratorError < Exception
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile ~/.gitignore_global
|
6
|
+
|
7
|
+
# Ignore bundler config
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore the default SQLite database.
|
11
|
+
/db/*.sqlite3
|
12
|
+
|
13
|
+
# Ignore all logfiles and tempfiles.
|
14
|
+
/log/*.log
|
15
|
+
/tmp
|
File without changes
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
<%= app_const %>.load_tasks
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
require 'nezu/generators/application/app_generator'
|
4
|
+
|
5
|
+
module Nezu
|
6
|
+
module Generators
|
7
|
+
|
8
|
+
configatron.template_paths = [File.join(configatron.gem_base_dir, 'lib/nezu/generators/application/templates')] + ENV['NEZU_TEMPLATES'].to_s.split(':')
|
9
|
+
configatron.file_suffixes = %w(tt)
|
10
|
+
|
11
|
+
def template_to(filename) # e.g. "config/amqp.yml"
|
12
|
+
dirname = File.join(configatron.destination_root, File.dirname(filename))
|
13
|
+
source_file = find_template(filename)
|
14
|
+
if source_file
|
15
|
+
FileUtils.mkdir_p(dirname)
|
16
|
+
|
17
|
+
if configatron.file_suffixes.include?(source_file.split('.')[-1])
|
18
|
+
e = ERB.new(File.read(source_file))
|
19
|
+
File.open(File.join(configatron.destination_root, filename.sub(/\.tt$/,'')), File::CREAT|File::TRUNC|File::WRONLY) do |f|
|
20
|
+
f.write(e.result(configatron.binding))
|
21
|
+
end
|
22
|
+
else
|
23
|
+
FileUtils.cp(source_file, dirname)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def find_template(filename)
|
31
|
+
candidates = configatron.template_paths.map do |path|
|
32
|
+
[File.join(path, filename)] +
|
33
|
+
configatron.file_suffixes.map do |suffix|
|
34
|
+
File.join(path, filename) + '.' + suffix
|
35
|
+
end
|
36
|
+
end.flatten
|
37
|
+
|
38
|
+
until candidates[-1].nil? || File.exist?(candidates[-1])
|
39
|
+
candidates.pop
|
40
|
+
end
|
41
|
+
candidates[-1]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
data/lib/nezu/runner.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
require 'amqp'
|
6
|
+
require "bunny"
|
7
|
+
require 'json'
|
8
|
+
require 'nezu/runtime/worker'
|
9
|
+
require 'nezu/runtime/consumer'
|
10
|
+
require 'nezu/runtime/producer'
|
11
|
+
require 'nezu/runtime/recipient'
|
12
|
+
|
13
|
+
$: << File.expand_path('./lib')
|
14
|
+
$: << File.expand_path('./app')
|
15
|
+
$: << File.expand_path('.')
|
16
|
+
|
17
|
+
|
18
|
+
Signal.trap("INT") { connection.close { EventMachine.stop } ; exit}
|
19
|
+
|
20
|
+
module Nezu
|
21
|
+
class CustomLogFormatter
|
22
|
+
SEVERITY_TO_COLOR_MAP = {'DEBUG'=>'0;37', 'INFO'=>'32', 'WARN'=>'33', 'ERROR'=>'31', 'FATAL'=>'31', 'UNKNOWN'=>'37'}
|
23
|
+
TIME_FORMAT = "%Y-%m-%d %H:%M:%S."
|
24
|
+
HOST = %x(hostname).chomp
|
25
|
+
APP = File.basename(Dir.pwd)
|
26
|
+
|
27
|
+
def call(severity, time, progname, msg)
|
28
|
+
formatted_severity = sprintf("%-5s","#{severity}")
|
29
|
+
formatted_time = time.strftime(TIME_FORMAT) << time.usec.to_s[0..2].rjust(3)
|
30
|
+
color = SEVERITY_TO_COLOR_MAP[severity]
|
31
|
+
if msg.kind_of?(Exception)
|
32
|
+
"#{formatted_time} #{HOST} #{APP}[#{$$}][\033[#{color}m#{formatted_severity}\033[0m] #{msg.to_s}\n" +
|
33
|
+
msg.backtrace.map do |bt_line|
|
34
|
+
"#{formatted_time} #{HOST} #{APP}[#{$$}][\033[#{color}m#{formatted_severity}\033[0m] #{bt_line.strip}"
|
35
|
+
end.join("\n")
|
36
|
+
else
|
37
|
+
"#{formatted_time} #{HOST} #{APP}[#{$$}][\033[#{color}m#{formatted_severity}\033[0m] #{msg.strip}\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
log_target = {
|
42
|
+
'development' => STDOUT,
|
43
|
+
'test' => nil,
|
44
|
+
'production' => File.expand_path(File.join('log/', 'nezu.log'))
|
45
|
+
}
|
46
|
+
LOGGER = Logger.new(log_target[Nezu.env])
|
47
|
+
LOGGER.formatter = CustomLogFormatter.new
|
48
|
+
|
49
|
+
def self.try(&block)
|
50
|
+
yield
|
51
|
+
rescue Exception => e
|
52
|
+
Nezu::LOGGER.warn("[Nezu Runner] Nezu.try failed")
|
53
|
+
Nezu::LOGGER.warn(e)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Dir.glob(File.join('config', '*.yml')).each do |yaml_file|
|
58
|
+
yaml = YAML.load_file(yaml_file)[Nezu.env]
|
59
|
+
configatron.configure_from_hash(File.basename(yaml_file.sub(/.yml/, '')) => yaml)
|
60
|
+
end
|
61
|
+
|
62
|
+
Nezu::LOGGER.info("[Nezu Runner] initializing...")
|
63
|
+
|
64
|
+
module Nezu
|
65
|
+
class Runner
|
66
|
+
def initialize
|
67
|
+
Nezu::LOGGER.debug("[Nezu Runner] initialize....")
|
68
|
+
Nezu.try {require "config/nezu"}
|
69
|
+
AMQP.start(configatron.amqp.url) do |connection, open_ok|
|
70
|
+
Nezu::LOGGER.debug("[Nezu Runner] AMQP connection #{configatron.amqp.url}")
|
71
|
+
channel = AMQP::Channel.new(connection, :auto_recovery => true)
|
72
|
+
Nezu::LOGGER.debug("[Nezu Runner] AMQP channel #{channel}")
|
73
|
+
Nezu::Runtime::Consumer.descendants.each do |consumer|
|
74
|
+
Nezu::LOGGER.debug("[Nezu Runner] Consumer.descendants: ##{consumer.to_s}")
|
75
|
+
worker = Nezu::Runtime::Worker.new(channel, consumer.new)
|
76
|
+
worker.start
|
77
|
+
end
|
78
|
+
end
|
79
|
+
#rescue => e
|
80
|
+
#Nezu::LOGGER.error(e)
|
81
|
+
#self.class.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Nezu::LOGGER.info("[Nezu Runner] ready")
|
87
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Nezu
|
2
|
+
module Runtime
|
3
|
+
class Consumer
|
4
|
+
def self.inherited(subclass)
|
5
|
+
subclass.class_eval {cattr_accessor :queue_name}
|
6
|
+
subclass.queue_name = ''
|
7
|
+
subclass.queue_name << "#{configatron.amqp.queue_prefix}." unless configatron.amqp.queue_prefix.nil?
|
8
|
+
subclass.queue_name << subclass.to_s.gsub(/::/, '.').underscore
|
9
|
+
subclass.queue_name << ".#{configatron.amqp.queue_postfix}" unless configatron.amqp.queue_postfix.nil?
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.descendants
|
13
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle_message(metadata, payload)
|
17
|
+
Nezu::LOGGER.debug("NEZU Consumer[#{self.class}] payload: #{payload}")
|
18
|
+
params = JSON.parse(payload.to_s)
|
19
|
+
action = params.delete('__action')
|
20
|
+
reply_to = params.delete('__reply_to')
|
21
|
+
result = self.send(action.to_sym, params)
|
22
|
+
if reply_to
|
23
|
+
result.reverse_merge!('__action' => "#{action}_result")
|
24
|
+
recipient = Nezu::Runtime::Recipient.new(reply_to)
|
25
|
+
Nezu::LOGGER.debug("sending result #{result}of #{action} to #{recipient}")
|
26
|
+
recipient.push!(result)
|
27
|
+
end
|
28
|
+
rescue NoMethodError => e
|
29
|
+
Nezu::LOGGER.error(e.to_s)
|
30
|
+
e.backtrace.each {|bt_line| Nezu::LOGGER.error(bt_line)}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nezu
|
2
|
+
module Runtime
|
3
|
+
class Producer
|
4
|
+
def self.inherited(subclass)
|
5
|
+
subclass.class_eval {cattr_accessor :queue_name} #:exchange_name?
|
6
|
+
subclass.queue_name = ''
|
7
|
+
subclass.queue_name << "#{configatron.amqp.queue_prefix}." unless configatron.amqp.queue_prefix.nil?
|
8
|
+
subclass.queue_name << subclass.to_s.gsub(/::/, '.').underscore
|
9
|
+
subclass.queue_name << ".#{configatron.amqp.queue_postfix}" unless configatron.amqp.queue_postfix.nil?
|
10
|
+
subclass.queue_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.descendants
|
14
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.push!(params = {})
|
18
|
+
conn = Bunny.new(configatron.amqp.url)
|
19
|
+
conn.start
|
20
|
+
ch = conn.create_channel
|
21
|
+
q = ch.queue(queue_name)
|
22
|
+
q.publish(params.to_json, :content_type => 'application/json')
|
23
|
+
conn.stop
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Nezu
|
2
|
+
module Runtime
|
3
|
+
class Recipient
|
4
|
+
def self.new(q)
|
5
|
+
Nezu::Runtime::Producer.descendants.select {|producer| producer.queue_name == q}[0] || (raise RecipientError.does_not_exist(q))
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class RecipientError < RuntimeError
|
10
|
+
def self.does_not_exist(q)
|
11
|
+
message = %Q(
|
12
|
+
The class "#{q.classify}" doesn`t exist or is not a child of "Nezu::Runtime::Producer".
|
13
|
+
Please create one in \"app/producers/#{q}.rb\" with the content of at least:
|
14
|
+
|
15
|
+
class #{q.classify} < Nezu::Runtime::Producer
|
16
|
+
end
|
17
|
+
).gsub(/^\s*/, '')
|
18
|
+
self.new(message)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Nezu
|
2
|
+
module Runtime
|
3
|
+
class Worker
|
4
|
+
def initialize(channel, consumer = Consumer.new)
|
5
|
+
@queue_name = consumer.class.queue_name
|
6
|
+
Nezu::LOGGER.info("queue name: #{@queue_name}")
|
7
|
+
@channel = channel
|
8
|
+
@channel.on_error(&method(:handle_channel_exception))
|
9
|
+
@consumer = consumer
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
Nezu::LOGGER.info("[Nezu Worker] #{@queue_name}")
|
14
|
+
@queue = @channel.queue(@queue_name, :exclusive => false)
|
15
|
+
@queue.subscribe(&@consumer.method(:handle_message))
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_channel_exception(channel, channel_close)
|
19
|
+
Nezu::LOGGER.error("Oops... a channel-level exception: code = #{channel_close.reply_code}, message = #{channel_close.reply_text}")
|
20
|
+
end # handle_channel_exception(channel, channel_close)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|