king_soa 0.0.2 → 0.0.3

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/README.rdoc CHANGED
@@ -1,55 +1,124 @@
1
1
  = KingSoa
2
2
 
3
- Creating a SOA requires a centralized location to define all services within the
4
- SOA. Furthermore you want to know where those services live.
3
+ KingSoa orchestrates a SOA landscape, by knowing where services live and how to
4
+ call them.
5
5
 
6
- == Tech details
6
+ == Why?
7
7
 
8
- the soa registry is keeping a bunch of service objects which know where a method
9
- lives. Methods are classes with an self.perform method and can be located local,
10
- remote(http) or beeing put onto a queue
8
+ While your app is growing you stuff more and more in it, unrelated to its core
9
+ business intelligence. You'll end up with an monolythic clumsy piece, getting
10
+ harder to handle every day. Just think of: scalability, testing, deployment, ..
11
11
 
12
+ To keep it clean a division of responsibilities, and with it a separation into
13
+ smaller parts, is needed. But now you've got a communication problem, because
14
+ each part needs to know about the others. This is where KingSoa enters the stage.
12
15
 
13
16
 
14
17
  == Install
15
18
 
16
19
  gem install king_soa
17
20
 
21
+ == Dependencies
22
+
23
+ Needed gems:
24
+
25
+ * resque => When a service has a queue set, its enqueued via resque
26
+ * typhoeus => making http requests to remotely located services
27
+ * json => all arguments of a service call are json encoded
28
+
18
29
  == Define services
19
30
 
20
- === Low Level
31
+ The service registry(KingSoa::Registry) is keeping track of available
32
+ services and behaves more or less like an array. Be aware that KingSoa::Registry
33
+ is a singleton, so that the rack middleware and your app are seeing the same.
34
+
35
+ A service (KingSoa::Service) has a name and knows how its gonna be called.
36
+ A service call goes out to a class named like the CamelCased service.name with
37
+ an self.perform method. Depending on the service settings it can be located
38
+ local, remote(http) or beeing put onto a queue.
21
39
 
22
40
  You can define services anywhere in your app and add them to the service
23
- registry.
24
- Be aware that the registry is a singleton, so that the rack middleware and your
25
- app are seeing the same :
26
- # create the service
27
- service = KingSoa::Service.new(:name=>:increment_usage,
28
- :url=>'http://localhost:4567',
29
- :auth_key=>'12345')
30
- # register
31
- KingSoa::Registry << service
32
-
33
- # somewhere in your app just call your service method
34
- KingSoa.increment_usage(12)
35
-
36
- A service name is always required. If the service is to be called remotely you
37
- must add a url and an auth_key.
38
- The transport is done via http calls, so to make it secure you should either use
39
- https in public or hide the servers somwhere on your farm.
41
+ registry. This should most likely be done in an initalizer(Rails).
42
+
43
+ # A remote service MUST have an url and an auth key set
44
+ a = KingSoa::Service.new(:name => :increment_usage,
45
+ :url => 'http://localhost:4567',
46
+ :auth => '12345')
47
+
48
+ # A local service calling CrunchImage.perform
49
+ b = KingSoa::Service.new(:name => :crunch_image)
50
+
51
+ # A queued service MUST have a queue name, and of course you should have a worker looking for it
52
+ c = KingSoa::Service.new(:name => :delete_user,
53
+ :queue => :deletions)
54
+ # register all of them
55
+ KingSoa::Registry << a << b << c
56
+
57
+ # somewhere in your app just call the services
58
+ KingSoa.increment_usage(12)
59
+ KingSoa.crunch_image(image_path)
60
+ KingSoa.delete_user(user_id)
61
+
62
+ === Remote Services
63
+
64
+ The transport is done via http calls. All http calls have an authentication key
65
+ to provide some minimal access restriction. To make it secure you should either
66
+ use https in public or hide the endpoints somwhere on your farm.
67
+
68
+ Service endpoints receiving such calls need to use the provided rack middleware.
69
+ The middleware is doing the authentication, executing the service class and
70
+ returns values or errors.
71
+
72
+ === Local Services
73
+
74
+ A local service calls a class with the CamelCased service name. This class MUST
75
+ have a self.perform method which receives all of the givven arguments.
76
+
77
+ === Queued Services
78
+
79
+ The service is put onto a resque queue and somewhere in you cloud you should
80
+ have a worker looing for it. The service class should also have the resque
81
+ @queue attribute set so the job can be resceduled if it fails.
40
82
 
41
83
  == Integration
42
84
 
85
+ Just think of a buch of small sinatra or specialized rails apps, each having
86
+ some internal services and consuming services from others.
87
+
43
88
  === Rails
44
89
 
90
+ Add the middleware(application.rb/environment.rb) if you want to receive calls.
91
+ require 'king_soa'
92
+ config.middleware.use KingSoa::Rack::Middleware
93
+
94
+ Setup services for example in an initializer reading a services.yml file. For
95
+ now there is no convinience loading method and no proposed yml format.
96
+ #services.yml
97
+ sign_document:
98
+ queue: signings
99
+ send_sms:
100
+ url: 'http://messaging.localhost:3000'
101
+ auth: '12345678'
102
+
103
+ # king_soa_init
104
+ service_defs = YAML.load_file(File.join(RAILS_ROOT, 'config', 'services.yml'))
105
+ service_defs.each do |k, v|
106
+ opts = { :name => k }
107
+ [:url, :auth, :queue].each do |opt|
108
+ opts[opt] = v[opt.to_s] if v[opt.to_s]
109
+ end
110
+ KingSoa::Registry << KingSoa::Service.new(opts)
111
+ end
45
112
 
46
113
  === Sinatra
47
114
 
48
115
  Take a look at spec/server/app where you can see a minimal sinatra implementation
49
116
  The base is just:
117
+
50
118
  require 'king_soa'
51
119
  use KingSoa::Rack::Middleware
52
-
120
+
121
+ The service definition should of course also be done, see rails example.
53
122
 
54
123
  == Note on Patches/Pull Requests
55
124
 
data/lib/king_soa.rb CHANGED
@@ -8,43 +8,21 @@ require 'king_soa/registry'
8
8
  require 'king_soa/service'
9
9
  require 'king_soa/rack/middleware'
10
10
 
11
- # Define available services.
12
- #
13
- # service:
14
- # name: sign_document
15
- # url: "https://msg.salesking.eu"
16
- # auth: 'a-long-random-string'
17
- # queue: a-queue-name
18
- #
19
- #
20
- # method: save_signed_document
21
- # url: "https://www.salesking.eu/soa"
22
- #
23
- #
24
- # after defining your services you can call each of them with
25
- #
26
- # <tt>KingSoa.service_name(args)</tt>
27
- #
28
- # KingSoa.sign_document(counter)
29
- # current_number = Hoth::Services.value_of_counter(counter)
30
- # created_account = Hoth::Services.create_account(account)
31
- #
32
11
  module KingSoa
33
12
 
34
13
  class << self
35
-
36
- def init_from_hash(services)
37
- # create service
38
- end
39
14
 
40
- # Locate service by a given name
15
+ # Locate service by a given name:
16
+ # KingSoa.find(:my_service_name)
41
17
  # ==== Parameter
42
18
  # service<String|Symbol>:: the name to lookup
43
19
  def find(service)
44
20
  Registry[service]
45
21
  end
46
22
 
47
- # this is where the services get called
23
+ # This is where the services get called.
24
+ # Tries to locate the service in the registry and if found call its perform
25
+ # method
48
26
  def method_missing(meth, *args, &blk) # :nodoc:
49
27
  if service = Registry[meth]
50
28
  service.perform(*args)
@@ -33,17 +33,24 @@ module KingSoa
33
33
  @services ||= []
34
34
  end
35
35
 
36
- # Add a new method onto the stack
36
+ # Add a new service onto the stack
37
+ # === Parameter
38
+ # service<KingSoa::Service>:: the service to add
37
39
  def <<(service)
38
40
  (services || []) << service
39
41
  end
40
42
 
41
43
  # Get a method by a given name
44
+ # === Parameter
45
+ # service_name<String|Symbol>:: the service to find
46
+ # === Returns
47
+ # <KingSoa::Service> or <nil>
42
48
  def [](service_name)
43
49
  name = service_name.to_sym
44
50
  services.detect {|s| s.name == name }
45
51
  end
46
52
 
53
+ # untested
47
54
  def group(service_name)
48
55
  name = service_name.to_sym
49
56
  # srvs = []
@@ -31,7 +31,10 @@ module KingSoa
31
31
  Resque::Job.create(queue, local_class_name, *args)
32
32
  end
33
33
 
34
- # Call a method: remote over http, local or put a job onto a queue
34
+ # Call a method:
35
+ # * remote over http
36
+ # * local by calling perform method on a class
37
+ # * put a job onto a queue
35
38
  # === Parameter
36
39
  # args:: whatever arguments the service methods recieves. Those are later json
37
40
  # encoded for remote or queued methods
@@ -45,6 +48,7 @@ module KingSoa
45
48
  end
46
49
  end
47
50
 
51
+ # The local class, if found
48
52
  def local_class
49
53
  @local_class ||= begin
50
54
  local_class_name.constantize
@@ -53,7 +57,8 @@ module KingSoa
53
57
  end
54
58
  end
55
59
 
56
- # Return the classname infered from service name
60
+ # Return the classname infered from the camelized service name.
61
+ # A service named: save_attachment => class SaveAttachment
57
62
  def local_class_name
58
63
  self.name.to_s.camelize
59
64
  end
@@ -16,7 +16,7 @@ describe KingSoa::Rack::Middleware do
16
16
  rack_response = middleware.call env
17
17
  rack_response.first.should == 500 #status code
18
18
  rack_response.last.should be_a_kind_of(Array)
19
- rack_response.last.first.should == "{\"error\":\"An error occurred! (Missing rack.input)\"}"
19
+ rack_response.last.first.should == "{\"error\":\"An error occurred => Missing rack.input\"}"
20
20
  end
21
21
 
22
22
  xit "should handle result" do
@@ -10,7 +10,6 @@ describe KingSoa::Service do
10
10
  end
11
11
 
12
12
  describe KingSoa::Service, 'local request' do
13
-
14
13
  it "should call service" do
15
14
  s = KingSoa::Service.new(:name=>:local_soa_class)
16
15
  s.perform(1,2,3).should == [1,2,3]
@@ -26,7 +25,6 @@ describe KingSoa::Service, 'queued' do
26
25
  end
27
26
 
28
27
  describe KingSoa::Service, 'remote request' do
29
-
30
28
  before :all do
31
29
  start_test_server
32
30
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Georg Leciejewski
@@ -42,7 +42,7 @@ dependencies:
42
42
  type: :runtime
43
43
  version_requirements: *id002
44
44
  - !ruby/object:Gem::Dependency
45
- name: rspec
45
+ name: resque
46
46
  prerelease: false
47
47
  requirement: &id003 !ruby/object:Gem::Requirement
48
48
  requirements:
@@ -51,8 +51,32 @@ dependencies:
51
51
  segments:
52
52
  - 0
53
53
  version: "0"
54
- type: :development
54
+ type: :runtime
55
55
  version_requirements: *id003
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ prerelease: false
59
+ requirement: &id004 !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ type: :development
67
+ version_requirements: *id004
68
+ - !ruby/object:Gem::Dependency
69
+ name: rack
70
+ prerelease: false
71
+ requirement: &id005 !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ type: :development
79
+ version_requirements: *id005
56
80
  description: |
57
81
  Creating a SOA requires a centralized location to define all services within the
58
82
  SOA. KingSoa takes care of keeping services in a service registry and knows how to call them.