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



241
242
243
244
245
# File 'lib/right_agent/clients/right_http_client.rb', line 241

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



225
226
227
228
229
230
231
# File 'lib/right_agent/clients/right_http_client.rb', line 225

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

  • :exception_callback (Proc)

    for unexpected exceptions with following parameters:

    Exception

    exception raised

    Packet, NilClass

    packet being processed

    Agent, NilClass

    agent in which exception occurred

Returns:

  • (TrueClass)

    always true

Raises:

  • (ArgumentError)

    no auth client



62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/right_agent/clients/right_http_client.rb', line 62

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:



188
189
190
191
# File 'lib/right_agent/clients/right_http_client.rb', line 188

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:



169
170
171
172
# File 'lib/right_agent/clients/right_http_client.rb', line 169

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:



111
112
113
114
115
# File 'lib/right_agent/clients/right_http_client.rb', line 111

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:



148
149
150
151
152
# File 'lib/right_agent/clients/right_http_client.rb', line 148

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



196
197
198
# File 'lib/right_agent/clients/right_http_client.rb', line 196

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



255
256
257
258
259
260
261
262
# File 'lib/right_agent/clients/right_http_client.rb', line 255

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



210
211
212
213
214
# File 'lib/right_agent/clients/right_http_client.rb', line 210

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