nezu 0.4.13
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/.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
|
+
|