nezu 0.4.13

Sign up to get free protection for your applications and to get access to all the features.
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
+