Class: RightScale::RightHttpClient

Inherits:
Object
  • Object
show all
Includes:
RightSupport::Ruby::EasySingleton
Defined in:
lib/right_agent/clients/right_http_client.rb

Overview

HTTP interface to RightNet router and to RightNet services in RightApi It is intended for use by instance agents and infrastructure servers The interface supports sending requests and sending/receiving events Events are received over a WebSocket if possible, otherwise via long-polling Requests to RightNet and RightApi are automatically retried to overcome connectivity failures A status callback is provided so that the user of this client can take action (e.g., queue requests) when connectivity is lost Health checks are sent periodically to try to recover from connectivity failures

Instance Method Summary collapse

Instance Method Details

#close(scope = :all) ⇒ TrueClass

Take any actions necessary to quiesce client interaction in preparation for agent termination but allow any active requests to complete Only router and api clients are closed, not auth client

Parameters:

  • scope (Symbol) (defaults to: :all)

    of close action: :receive for just closing receive side of client, :all for closing both receive and send side; defaults to :all

Returns:

  • (TrueClass)

    always true



237
238
239
240
241
# File 'lib/right_agent/clients/right_http_client.rb', line 237

def close(scope = :all)
  @router.close(scope) if @router
  @api.close(scope) if @api
  true
end

#communicated(types = []) { ... } ⇒ TrueClass

Set callback for each successful communication excluding health checks

Parameters:

  • types (Array) (defaults to: [])

    of server: :auth, :api, or :router; defaults to all

Yields:

  • required block executed after successful communication

Returns:

  • (TrueClass)

    always true

Raises:

  • (RuntimeError)

    init was not called



221
222
223
224
225
226
227
# File 'lib/right_agent/clients/right_http_client.rb', line 221

def communicated(types = [], &callback)
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  @auth.communicated(&callback) if types.empty? || types.include?(:auth)
  @api.communicated(&callback) if @api && (types.empty? || types.include?(:api))
  @router.communicated(&callback) if @router && (types.empty? || types.include?(:router))
  true
end

#init(auth_client, options = {}) ⇒ TrueClass

Initialize RightNet client Must be called before any other functions are usable

Parameters:

  • auth_client (AuthClient)

    providing authorization session for HTTP requests

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

    a customizable set of options

Options Hash (options):

  • :open_timeout (Numeric)

    maximum wait for connection

  • :request_timeout (Numeric)

    maximum wait for response

  • :listen_timeout (Numeric)

    maximum wait for event when long-polling

  • :retry_timeout (Numeric)

    maximum before stop retrying

  • :retry_intervals (Array)

    between successive retries

  • :retry_enabled (Boolean)

    for requests that fail to connect or that return a retry result

  • :non_blocking (Boolean)

    i/o is to be used for HTTP requests by applying EM::HttpRequest and fibers instead of RestClient; requests remain synchronous

  • :long_polling_only (Boolean)

    never attempt to create a WebSocket, always long-polling instead

  • :filter_params (Array)

    symbols or strings for names of request parameters whose values are to be hidden when logging; also applied to contents of any parameters named :payload

Returns:

  • (TrueClass)

    always true

Raises:

  • (ArgumentError)

    no auth client



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/right_agent/clients/right_http_client.rb', line 58

def init(auth_client, options = {})
  raise ArgumentError, "No authorization client provided" unless auth_client.is_a?(AuthClient)
  @status = {}
  callback = lambda { |type, state| update_status(type, state) }
  @auth = auth_client
  @status[:auth] = @auth.status(&callback)
  @router = RouterClient.new(@auth, options)
  @status[:router] = @router.status(&callback)
  if @auth.api_url
    @api = ApiClient.new(@auth, options)
    @status[:api] = @api.status(&callback)
  end
  true
end

#listen(routing_keys) {|event| ... } ⇒ TrueClass

Receive events via an HTTP WebSocket if available, otherwise via an HTTP long-polling

Parameters:

  • routing_keys (Array, NilClass)

    for event sources of interest with nil meaning all

Yields:

  • (event)

    required block called each time event received

Yield Parameters:

Returns:

  • (TrueClass)

    always true, although normally never returns

Raises:



184
185
186
187
# File 'lib/right_agent/clients/right_http_client.rb', line 184

def listen(routing_keys, &handler)
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  @router.listen(routing_keys, &handler)
end

#notify(event, routing_keys) ⇒ TrueClass

Route event Use WebSocket if possible Do not block this request even if in the process of closing

Parameters:

  • event (Hash)

    to send

  • routing_keys (Array, NilClass)

    as strings to assist router in delivering event to interested parties

Returns:

  • (TrueClass)

    always true

Raises:



165
166
167
168
# File 'lib/right_agent/clients/right_http_client.rb', line 165

def notify(event, routing_keys)
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  @router.notify(event, routing_keys)
end

#push(type, payload = nil, target = nil, options = {}) ⇒ NilClass

Route a request to a single target or multiple targets with no response expected Persist the request en route to reduce the chance of it being lost at the expense of some additional network overhead Enqueue the request if the target is not currently available Never automatically retry the request if there is the possibility of it being duplicated Set time-to-live to be forever

Parameters:

  • type (String)

    of request as path specifying actor and action

  • payload (Hash, NilClass) (defaults to: nil)

    for request

  • target (String, Hash, NilClass) (defaults to: nil)

    for request, which may be identity of specific target, hash for selecting potentially multiple targets, or nil if routing solely using type; hash may contain:

    Array

    :tags that must all be associated with a target for it to be selected

    Hash

    :scope for restricting routing which may contain:

    Integer

    :account id that agents must be associated with to be included

    Integer

    :shard id that agents must be in to be included, or if value is

    Packet::GLOBAL, ones with no shard id
    
    Symbol

    :selector for picking from qualified targets: :any or :all;

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

    a customizable set of options

Options Hash (options):

  • :request_uuid (String)

    uniquely identifying this request; defaults to randomly generated

  • :time_to_live (Numeric)

    seconds before request expires and is to be ignored; non-positive value or nil means never expire

Returns:

  • (NilClass)

    always nil since there is no expected response to the request

Raises:



107
108
109
110
111
# File 'lib/right_agent/clients/right_http_client.rb', line 107

def push(type, payload = nil, target = nil, options = {})
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  client = (@api && @api.support?(type)) ? @api : @router
  client.push(type, payload, target, options)
end

#request(type, payload = nil, target = nil, options = {}) ⇒ Result, NilClass

Route a request to a single target with a response expected Automatically retry the request if a response is not received in a reasonable amount of time or if there is a non-delivery response indicating the target is not currently available Timeout the request if a response is not received in time, typically configured to 30 sec Because of retries there is the possibility of duplicated requests, and these are detected and discarded automatically for non-idempotent actions Allow the request to expire per the agent’s configured time-to-live, typically 1 minute

Parameters:

  • type (String)

    of request as path specifying actor and action

  • payload (Hash, NilClass) (defaults to: nil)

    for request

  • target (String, Hash, NilClass) (defaults to: nil)

    for request, which may be identity of specific target, hash for selecting targets of which one is picked randomly, or nil if routing solely using type; hash may contain:

    Array

    :tags that must all be associated with a target for it to be selected

    Hash

    :scope for restricting routing which may contain:

    Integer

    :account id that agents must be associated with to be included

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

    a customizable set of options

Options Hash (options):

  • :request_uuid (String)

    uniquely identifying this request; defaults to randomly generated

  • :time_to_live (Numeric)

    seconds before request expires and is to be ignored; non-positive value or nil means never expire

Returns:

  • (Result, NilClass)

    response from request

Raises:



144
145
146
147
148
# File 'lib/right_agent/clients/right_http_client.rb', line 144

def request(type, payload = nil, target = nil, options = {})
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  client = (@api && @api.support?(type)) ? @api : @router
  client.request(type, payload, target, options)
end

#self_hrefString, NilClass

Resource href associated with the user of this client

Returns:

  • (String, NilClass)

    href or nil if unknown



192
193
194
# File 'lib/right_agent/clients/right_http_client.rb', line 192

def self_href
  @api.self_href if @api
end

#stats(reset = false) ⇒ Hash

Current statistics for this client

Parameters:

  • reset (Boolean) (defaults to: false)

    the statistics after getting the current ones

Returns:

  • (Hash)

    current statistics with keys “auth client stats”, “router client stats”, and optionally “api client stats”

Raises:

  • (RuntimeError)

    init was not called



251
252
253
254
255
256
257
258
# File 'lib/right_agent/clients/right_http_client.rb', line 251

def stats(reset = false)
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  stats = {}
  stats["auth stats"] = @auth.stats(reset)
  stats["router stats"] = @router.stats(reset)
  stats["api stats"] = @api.stats(reset) if @api
  stats
end

#status {|type, status| ... } ⇒ Hash

Record callback to be notified of status changes Multiple callbacks are supported

Yields:

  • (type, status)

    called when status changes (optional)

Yield Parameters:

  • type (Symbol)

    of client reporting status change: :auth, :api, or :router

  • state (Symbol)

    of client

Returns:

  • (Hash)

    status of various clients

Raises:

  • (RuntimeError)

    init was not called



206
207
208
209
210
# File 'lib/right_agent/clients/right_http_client.rb', line 206

def status(&callback)
  raise RuntimeError, "#{self.class.name}#init was not called" unless @auth
  @status_callbacks = (@status_callbacks || []) << callback if callback
  @status
end