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.
Files changed (64) hide show
  1. data/.document +5 -0
  2. data/.gitignore +13 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +77 -0
  5. data/README.md +14 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/bin/nezu +8 -0
  9. data/lib/nezu/cli.rb +43 -0
  10. data/lib/nezu/generators/application/MANIFEST +16 -0
  11. data/lib/nezu/generators/application/USAGE +15 -0
  12. data/lib/nezu/generators/application/app_generator.rb +37 -0
  13. data/lib/nezu/generators/application/templates/.gitignore +15 -0
  14. data/lib/nezu/generators/application/templates/Gemfile +9 -0
  15. data/lib/nezu/generators/application/templates/README.md +0 -0
  16. data/lib/nezu/generators/application/templates/Rakefile +7 -0
  17. data/lib/nezu/generators/application/templates/app/consumers/$app_name.rb.tt +4 -0
  18. data/lib/nezu/generators/application/templates/app/consumers/.gitkeep +0 -0
  19. data/lib/nezu/generators/application/templates/app/models/.gitkeep +0 -0
  20. data/lib/nezu/generators/application/templates/app/producers/.gitkeep +0 -0
  21. data/lib/nezu/generators/application/templates/config/amqp.yml.tt +9 -0
  22. data/lib/nezu/generators/application/templates/config/boot.rb.tt +6 -0
  23. data/lib/nezu/generators/application/templates/config/database.yml.tt +9 -0
  24. data/lib/nezu/generators/application/templates/config/initializers/.gitkeep +0 -0
  25. data/lib/nezu/generators/application/templates/config/nezu.rb.tt +11 -0
  26. data/lib/nezu/generators/application/templates/db/.gitkeep +0 -0
  27. data/lib/nezu/generators/application/templates/log/.gitkeep +0 -0
  28. data/lib/nezu/generators/application/templates/spec/.gitkeep +0 -0
  29. data/lib/nezu/generators.rb +45 -0
  30. data/lib/nezu/runner.rb +87 -0
  31. data/lib/nezu/runtime/consumer.rb +35 -0
  32. data/lib/nezu/runtime/producer.rb +28 -0
  33. data/lib/nezu/runtime/recipient.rb +24 -0
  34. data/lib/nezu/runtime/worker.rb +24 -0
  35. data/lib/nezu.rb +34 -0
  36. data/nezu.gemspec +25 -0
  37. data/spec/functional/generators/app_generator_spec.rb +52 -0
  38. data/spec/functional/generators_spec.rb +36 -0
  39. data/spec/functional/nezu_spec.rb +11 -0
  40. data/spec/functional/runner_spec.rb +0 -0
  41. data/spec/functional/runtime/consumer_spec.rb +54 -0
  42. data/spec/functional/runtime/producer_spec.rb +24 -0
  43. data/spec/functional/runtime/recipient_spec.rb +15 -0
  44. data/spec/integration/user_script_spec.rb +6 -0
  45. data/spec/spec_helper.rb +32 -0
  46. data/spec/support/lib/nezu/generators/application/templates/test_file.tt +2 -0
  47. data/spec/support/lib/nezu/generators/application/templates/test_file_without_suffix +0 -0
  48. data/spec/support/sample_project/.gitignore +15 -0
  49. data/spec/support/sample_project/Gemfile +9 -0
  50. data/spec/support/sample_project/README.md +0 -0
  51. data/spec/support/sample_project/Rakefile +7 -0
  52. data/spec/support/sample_project/app/consumers/.gitkeep +0 -0
  53. data/spec/support/sample_project/app/consumers/sample_project.rb +4 -0
  54. data/spec/support/sample_project/app/models/.gitkeep +0 -0
  55. data/spec/support/sample_project/app/producers/.gitkeep +0 -0
  56. data/spec/support/sample_project/config/amqp.yml +9 -0
  57. data/spec/support/sample_project/config/boot.rb +6 -0
  58. data/spec/support/sample_project/config/database.yml +9 -0
  59. data/spec/support/sample_project/config/initializers/.gitkeep +0 -0
  60. data/spec/support/sample_project/config/nezu.rb +11 -0
  61. data/spec/support/sample_project/db/.gitkeep +0 -0
  62. data/spec/support/sample_project/spec/.gitkeep +0 -0
  63. data/spec/support/tmp/.gitkeep +0 -0
  64. metadata +252 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,13 @@
1
+ *.sw?
2
+ *~
3
+ .DS_Store
4
+ .idea
5
+ coverage
6
+ pkg
7
+ rdoc
8
+ spec/debug.log
9
+ spec/*.db
10
+ TODO
11
+ log/
12
+ tmp/
13
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ puts File.join(File.expand_path('../..', __FILE__), 'lib')
3
+ $:.unshift(File.join(File.expand_path('../..', __FILE__), 'lib'))
4
+ ARGV << 'help' if ARGV.length == 0
5
+
6
+ require "nezu"
7
+ require "nezu/cli"
8
+
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
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+ gem 'activerecord'
3
+ gem 'nezu', :git => 'ssh://git@svn.talkyoo.net/nezu.git'
4
+
5
+ group :development, :test do
6
+ gem 'debugger'
7
+ gem 'rspec'
8
+ end
9
+
@@ -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
@@ -0,0 +1,4 @@
1
+ class <%= name_space %> < Nezu::Runtime::Consumer
2
+ #your app code here
3
+ end
4
+
@@ -0,0 +1,9 @@
1
+ development:
2
+ url: amqp://127.0.0.1
3
+ queue_prefix: talkyoo
4
+ queue_postfix: dev
5
+ production:
6
+ url: amqp://127.0.0.1
7
+ queue_prefix: talkyoo
8
+ queue_postfix: dev
9
+
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
+
6
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
@@ -0,0 +1,9 @@
1
+ development: &dev
2
+ adapter: sqlite
3
+ encoding: utf8
4
+ database: <%= app_name %>_development
5
+
6
+ production:
7
+ <<: *dev
8
+ database: <%= app_name %>_production
9
+
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+ if defined?(Bundler)
3
+ Bundler.require(:default, Nezu.env)
4
+ end
5
+
6
+ Dir.glob("**/*.rb").each do |f|
7
+ require f
8
+ end
9
+
10
+ LOGGER = Logger.new('log/<%= name_space %>.log')
11
+
@@ -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
+
@@ -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
+