class Google::Cloud::Env::LazyDict

@private

This expands on {LazyValue} by providing a lazy key-value dictionary. Each key uses a separate LazyValue; hence multiple keys can be in the process of computation concurrently and independently.

We keep this private for now so we can move it in the future if we need it to be available to other libraries. Currently it should not be used outside of Google::Cloud::Env.

Public Class Methods

new(retries: nil, &block) click to toggle source

Create a LazyDict.

You must pass a block that will be called to compute the value the first time it is accessed. The block takes the key as an argument and should evaluate to the value for that key, or raise an exception on error. To specify a value that expires, use {LazyValue.expiring_value}. To raise an exception that expires, use {LazyValue.raise_expiring_error}.

You can optionally pass a retry manager, which controls how subsequent accesses might try calling the block again if a compute attempt fails with an exception. A retry manager should either be an instance of {Retries} or an object that duck types it.

@param retries [Retries,Proc] A retry manager. The default is a retry

manager that tries only once. You can provide either a static
retry manager or a Proc that returns a retry manager.

@param block [Proc] A block that can be called to attempt to compute

the value given the key.
# File lib/google/cloud/env/lazy_value.rb, line 699
def initialize retries: nil, &block
  @retries = retries
  @compute_handler = block
  @key_values = {}
  @mutex = Thread::Mutex.new
end

Public Instance Methods

[](key, *extra_args)
Alias for: get
await(key, *extra_args, transient_errors: nil, max_tries: 1, max_time: nil) click to toggle source

This method calls {#get} repeatedly until a final result is available or retries have exhausted.

Note: this method spins on {#get}, although honoring any retry delay. Thus, it is best to call this only if retries are limited or a retry delay has been configured.

@param key [Object] the key @param extra_args [Array] extra arguments to pass to the block @param transient_errors [Array<Class>] An array of exception classes

that will be treated as transient and will allow await to
continue retrying. Exceptions omitted from this list will be
treated as fatal errors and abort the call. Default is
`[StandardError]`.

@param max_tries [Integer,nil] The maximum number of times this will

call {#get} before giving up, or nil for a potentially unlimited
number of attempts. Default is 1.

@param max_time [Numeric,nil] The maximum time in seconds this will

spend before giving up, or nil (the default) for a potentially
unlimited timeout.

@return [Object] the value @raise [Exception] if a fatal error happened, or retries have been

exhausted.
# File lib/google/cloud/env/lazy_value.rb, line 753
def await key, *extra_args, transient_errors: nil, max_tries: 1, max_time: nil
  lookup_key(key).await key, *extra_args,
                        transient_errors: transient_errors,
                        max_tries: max_tries,
                        max_time: max_time
end
expire!(key) click to toggle source

Force the cache for the given key to expire immediately, if computation is complete.

Any cached value will be cleared, the retry count is reset, and the next access will call the compute block as if it were the first access. Returns true if this took place. Has no effect and returns false if the computation is not yet complete (i.e. if a thread is currently computing, or if the last attempt failed and retries have not yet been exhausted.)

@param key [Object] the key @return [true,false] whether the cache was expired

# File lib/google/cloud/env/lazy_value.rb, line 785
def expire! key
  lookup_key(key).expire!
end
expire_all!() click to toggle source

Force the values for all keys to expire immediately.

@return [Array<Object>] A list of keys that were expired. A key is

*not* included if its computation is not yet complete (i.e. if a
thread is currently computing, or if the last attempt failed and
retries have not yet been exhausted.)
# File lib/google/cloud/env/lazy_value.rb, line 797
def expire_all!
  all_expired = []
  @mutex.synchronize do
    @key_values.each do |key, value|
      all_expired << key if value.expire!
    end
  end
  all_expired
end
get(key, *extra_args) click to toggle source

Returns the value for the given key. This will either return the value or raise an error indicating failure to compute the value. If the value was previously cached, it will return that cached value, otherwise it will either run the computation to try to determine the value, or wait for another thread that is already running the computation.

Any arguments beyond the initial key argument will be passed to the block if it is called, but are ignored if a cached value is returned.

@param key [Object] the key @param extra_args [Array] extra arguments to pass to the block @return [Object] the value @raise [Exception] if an error happened while computing the value

# File lib/google/cloud/env/lazy_value.rb, line 722
def get key, *extra_args
  lookup_key(key).get key, *extra_args
end
Also aliased as: []
internal_state(key) click to toggle source

Returns the current low-level state for the given key. Does not block for computation. See {LazyValue#internal_state} for details.

@param key [Object] the key @return [Array] the low-level state

# File lib/google/cloud/env/lazy_value.rb, line 767
def internal_state key
  lookup_key(key).internal_state
end
set!(key, value, lifetime: nil) click to toggle source

Set the cache value for the given key explicitly and immediately. If a computation is in progress, it is “detached” and its result will no longer be considered.

@param key [Object] the key @param value [Object] the value to set @param lifetime [Numeric] the lifetime until expiration in seconds,

or nil (the default) for no expiration.

@return [Object] the value

# File lib/google/cloud/env/lazy_value.rb, line 818
def set! key, value, lifetime: nil
  lookup_key(key).set! value, lifetime: lifetime
end

Private Instance Methods

lookup_key(key) click to toggle source

@private Ensures that exactly one LazyValue exists for the given key, and returns it.

# File lib/google/cloud/env/lazy_value.rb, line 829
def lookup_key key
  # Optimization: check for key existence and return quickly without
  # grabbing the mutex. This works because keys are never deleted.
  return @key_values[key] if @key_values.key? key

  @mutex.synchronize do
    if @key_values.key? key
      @key_values[key]
    else
      retries =
        if @retries.respond_to? :reset_dup
          @retries.reset_dup
        elsif @retries.respond_to? :call
          @retries.call
        end
      @key_values[key] = LazyValue.new retries: retries, &@compute_handler
    end
  end
end