king_soa 0.0.2 → 0.0.3

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