Class: IBM::Bluemix::ServiceDiscovery

Inherits:
Object
  • Object
show all
Defined in:
lib/ibm/bluemix/service_discovery.rb,
lib/ibm/bluemix/service_discovery/version.rb

Overview

ServiceDiscovery provides a simple interface to the IBM Bluemix Service Discovery service. The interface provides methods for all operations provided by Service Discovery as well as some helpers to make working with the service a little easier.

Constant Summary collapse

VERSION =
"0.1.3"
@@services =

cache of registered services

{}
@@heartbeats =

cache of threads running heartbeats

{}

Class Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(auth_token) ⇒ ServiceDiscovery

Create a new ServiceDiscovery instance.

Examples:

sd = ServiceDiscovery.new('token...')

Parameters:

  • auth_token (String)

    Valid ‘auth_token` from the IBM Bluemix Service Discovery service



53
54
55
56
57
58
59
60
61
62
# File 'lib/ibm/bluemix/service_discovery.rb', line 53

def initialize(auth_token)
  @auth_token = auth_token

  # defaults
  Unirest.default_header('Authorization', 'Bearer ' + @auth_token)
  Unirest.default_header('Accept','application/json')
  Unirest.default_header('Content-Type','application/json')

  Unirest.timeout(5) # 5s timeout
end

Class Attribute Details

.loggerObject

Logger function that should be overridden.

Examples:

logger.debug 'this is a debug message'


39
40
41
42
43
# File 'lib/ibm/bluemix/service_discovery.rb', line 39

def logger
  @logger ||= Logger.new($stdout).tap do |log|
    log.progname = self.name
  end
end

Instance Method Details

#delete(service_name) ⇒ Boolean

Deletes a service entry from Service Discovery

Examples:

sd.delete('sample_service')

Parameters:

  • service_name (String)

    The name of the microservice

Returns:

  • (Boolean)

    ‘true` if the service was removed, `false` otherwise



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/ibm/bluemix/service_discovery.rb', line 223

def delete(service_name)

  # error, we didn't register the service yet
  return false unless @@services.has_key? service_name

  service = @@services[service_name]
  ServiceDiscovery.logger.debug 'Deleting: ' + service.to_s

  begin
    response = Unirest.delete service['links']['self']
  rescue Exception => e
    #
    ServiceDiscovery.logger.debug "Exception: #{e.class} #{e.message}"
  end

  if response.code != 200
    #
    # Attempting to send a heartbeat for an expired instance will result in HTTP status code 410 (Gone).
  end
  @@services.delete service_name
  true
end

#discover(service_name) ⇒ Hash

Discovers the connection information for a given microservice.

Examples:

sd.discover('sample_service')

Parameters:

  • service_name (String)

    The name of the microservice

Returns:

  • (Hash)

    {

    "service_name":"my_service",
    "instances":[
    {
       "endpoint":
       {
          "type": "tcp",
          "value": "192.168.1.32:80",
       },
       "status": "UP",
       "last_heartbeat": "2015-05-01T08:28:06.801064+02:00",
       "metadata": {"key":"value"}
    }]
    

    }



329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/ibm/bluemix/service_discovery.rb', line 329

def discover(service_name)
  # curl -X GET -H "Authorization: bearer 12o191sqk5h***" https://servicediscovery.ng.bluemix.net/api/v1/services/my_service

  # {
  #    "service_name":"my_service",
  #    "instances":[
  #    {
  #       "endpoint":
  #       {
  #          "type": "tcp",
  #          "value": "192.168.1.32:80",
  #       },
  #       "status": "UP",
  #       "last_heartbeat": "2015-05-01T08:28:06.801064+02:00",
  #       "metadata": {"key":"value"}
  #    }]
  # }

  begin
    response = Unirest.get SERVICE_DISCOVERY_ENDPOINT + '/' + service_name
  rescue Exception => e
    #
    ServiceDiscovery.logger.debug "Exception: #{e.class} #{e.message}"
  end

  if response.code != 200
    #
    # Attempting to send a heartbeat for an expired instance will result in HTTP status code 410 (Gone).
  end

  response.body
end

#heartbeat(service_name, interval = 60) ⇒ Boolean

Set-up a separate Thread to send continuous heartbeats (renew) calls to indicate the service is alive.

Examples:

sd.heartbeat('sample_service', 45)

Parameters:

  • service_name (String)

    The name of the microservice

  • interval (Integer) (defaults to: 60)

    The number of seconds between heartbeats

Returns:

  • (Boolean)

    ‘true` if the heartbeat thread was started, `false` otherwise



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/ibm/bluemix/service_discovery.rb', line 181

def heartbeat(service_name, interval=60)

  # kill the existing thread
  unless @@heartbeats[service_name].nil?
    ServiceDiscovery.logger.debug 'killing an existing heartbeat thread'
    Thread.kill @@heartbeats[service_name]
  end

  # create a new thread that is going to run forever
  @@heartbeats[service_name] = Thread.new{
    while true
      # TODO: how to handle errors in the thread?
      ServiceDiscovery.logger.debug 'sending heartbeat'
      self.renew(service_name)
      sleep interval
    end
  }

  # # something happened?
  # true
end

#infoHash

Returns information about the current local state of Service Discovery. This includes information about the services and the heartbeats.

Examples:

sd.info

Returns:

  • (Hash)

    { services: [‘s1’, ‘s2’], heartbeats: [‘s1’] }



277
278
279
# File 'lib/ibm/bluemix/service_discovery.rb', line 277

def info
  { services: @@services.keys, heartbeats: heartbeats.keys }
end

#listHash

Get the current list of registered services within Service Discovery

Examples:

sd.list

Returns:

  • (Hash)

    { services: [‘s1’, ‘s2’] }



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/ibm/bluemix/service_discovery.rb', line 288

def list

  # curl -X GET -H "Authorization: bearer 12o191sqk5h***"https://servicediscovery.ng.bluemix.net/api/v1/services

  begin
    response = Unirest.get SERVICE_DISCOVERY_ENDPOINT
  rescue Exception => e
    #
    ServiceDiscovery.logger.debug "Exception: #{e.class} #{e.message}"
  end

  if response.code != 200
    #
    # Attempting to send a heartbeat for an expired instance will result in HTTP status code 410 (Gone).
  end

  response.body
end

#register(service_name, host, options = {}, meta = {}) ⇒ Hash

Register a service with Service Discovery

Examples:

sd = ServiceDiscovery.new('token...')
=> sd.register('sample_service', '192.168.1.100:8080', { ttl: 60, heartbeat: true }, {})

Parameters:

  • service_name (String)

    The name of the microservice

  • host (String)

    The host and port where the microservice can be reached at

  • options (Hash) (defaults to: {})

    Options to customize service discovery instance (see below)

  • meta (Hash) (defaults to: {})

    Metadata to store with the service registration

Options Hash (options):

  • :heartbeat (Boolean)

    Enable or disable automated heartbeat for the service

  • :ttl (Integer)

    Expire the service after this many seconds if a heartbeat has not been received. Hearbeat is automatically set to 30% of this value

Returns:

  • (Hash)

    Resulting payload from the call to Service Discovery



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/ibm/bluemix/service_discovery.rb', line 78

def register(service_name, host, options = {}, meta = {})

  begin
    response = Unirest.post SERVICE_REGISTRY_ENDPOINT,
                    parameters: {
                      service_name: service_name,
                      endpoint: {
                        type: 'tcp',
                        value: host
                      },
                      status: "UP",
                      ttl: options[:ttl] || 60,
                      metadata: meta
                    }.to_json
  rescue Exception => e
    # TODO: raise custom exception
    ServiceDiscovery.logger.debug "Exception: #{e.class} #{e.message}"
    return nil
  end

  # ServiceDiscovery.logger.debug response

  if response.code != 201
    #
    ServiceDiscovery.logger.error response.code
  end

  # TODO: validate the response.body has the right keys

  @@services[service_name] = response.body

  # response.code # Status code
  # response.headers # Response headers
  # response.body # Parsed body
  # response.raw_body # Unparsed body



  # '{"service_name":"my_service", "endpoint": { "type":"tcp", "value": "host:port" }, "status":"UP", "ttl":25, "metadata":{"key":"value"}}'

  # {
  #    "id":"6ae425dd79f1962e",
  #    "ttl":30,
  #    "links":{
  #       "self": "https://servicediscovery.ng.bluemix.net/api/v1/instances/6ae425dd79f1962e",
  #       "heartbeat": "https://servicediscovery.ng.bluemix.net/api/v1/instances/6ae425dd79f1962e/heartbeat",
  #    }
  # }

  # check if we should enable a heartbeat
  if options[:heartbeat] == true
    heartbeat_ttl = (options[:ttl] * 0.75).round
    self.heartbeat(service_name, heartbeat_ttl)
  end

  return @@services[service_name]
end

#renew(service_name) ⇒ Boolean

Send a heartbeat request to indicate the service is still alive and well

Examples:

sd.renew('sample_service')

Parameters:

  • service_name (String)

    The name of the microservice

Returns:

  • (Boolean)

    ‘true` if the service was renewed, `false` otherwise



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ibm/bluemix/service_discovery.rb', line 144

def renew(service_name)

  # error, we didn't register the service yet
  return false unless @@services.has_key? service_name

  service = @@services[service_name]

  begin
    ServiceDiscovery.logger.debug 'calling heartbeat url: ' + service['links']['heartbeat']
    response = Unirest.put service['links']['heartbeat'],
                    headers: {
                      'Content-Length': 0
                    }
  rescue Exception => e
    #
  end

  if response.code != 200
    #
    # Attempting to send a heartbeat for an expired instance will result in HTTP status code 410 (Gone).
    return false
  end

  # curl -X PUT -H "Authorization: Bearer 12o191sqk5h***" -H "Content-Length: 0" https://servicediscovery.ng.bluemix.net/api/v1/instances/6ae425dd79f1962e/heartbeat
  true
end

#resetBoolean

Resets the state of this service. This includes stopping any existing heartbeat Threads as well as deleting all registered services.

Examples:

sd.reset

Returns:

  • (Boolean)

    ‘true` if the reset was successful, `false` otherwise



254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/ibm/bluemix/service_discovery.rb', line 254

def reset

  # cancel any threads
  @@heartbeats.keys.each do |k|
    self.unheartbeat(k)
  end

  # delete all of the services
  @@services.keys.each do |k|
    self.delete(k)
  end

  true
end

#unheartbeat(service_name) ⇒ Boolean

Stops a previously established heartbeat Thread

Examples:

sd.unheartbeat('sample_service')

Parameters:

  • service_name (String)

    The name of the microservice

Returns:

  • (Boolean)

    ‘true` if the heartbeat thread was stopped, `false` otherwise



211
212
213
# File 'lib/ibm/bluemix/service_discovery.rb', line 211

def unheartbeat(service_name)
  Thread.kill @@heartbeats[service_name]
end