Module: RedisQueuedLocks::Acquirer::AcquireLock::YieldExpire Private

Included in:
RedisQueuedLocks::Acquirer::AcquireLock, LockSeriesPoC
Defined in:
lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Since:

  • 1.3.0

Version:

  • 1.7.0

Defined Under Namespace

Modules: LogVisitor

Constant Summary collapse

DECREASE_LOCK_PTTL =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Returns:

  • (String)

Since:

  • 1.3.0

<<~LUA_SCRIPT.strip.tr("\n", '').freeze
  local new_lock_pttl = redis.call("PTTL", KEYS[1]) - ARGV[1];
  return redis.call("PEXPIRE", KEYS[1], new_lock_pttl);
LUA_SCRIPT

Instance Method Summary collapse

Instance Method Details

#yield_expire(redis, logger, lock_key, acquirer_id, host_id, access_strategy, timed, ttl_shift, ttl, queue_ttl, meta, log_sampled, instr_sampled, should_expire, should_decrease) { ... } ⇒ Any, NilClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

rubocop:disable Metrics/MethodLength

Parameters:

  • redis (RedisClient) —

    Redis connection.

  • logger (::Logger, #debug) —

    Logger object.

  • lock_key (String) —

    Obtained lock key that should be expired.

  • acquirer_id (String) —

    Acquirer identifier.

  • host_id (String) —

    Host identifier.

  • access_strategy (Symbol) —

    Lock obtaining strategy.

  • timed (Boolean) —

    Should the lock be wrapped by Timeout with with lock's ttl

  • ttl_shift (Numeric) —

    Lock's TTL shifting. Should affect block's ttl. In millisecodns.

  • ttl (Integer, NilClass) —

    Lock's time to live (in ms). Nil means "without timeout".

  • queue_ttl (Integer) —

    Lock request lifetime.

  • meta (NilClass, Hash<String|Symbol,Any>) —

    Custom metadata wich is passed to the lock data;

  • log_sampled (Boolean) —

    Should the logic be logged or not.

  • instr_sampled (Boolean) —

    Should the logic be instrumented or not.

  • should_expire (Boolean) —

    Should the lock be expired after the block invocation.

  • should_decrease (Boolean) —
    • Should decrease the lock TTL after the lock invocation;
    • It is suitable for extendable reentrant locks;

Yields:

  • Custom logic that should be invoked under the obtained lock.

Yield Returns:

  • (Any)

Returns:

  • (Any, NilClass) —

    nil is returned when no block parametr is provided.

Since:

  • 1.3.0

Version:

  • 1.9.0



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
# File 'lib/redis_queued_locks/acquirer/acquire_lock/yield_expire.rb', line 43

def yield_expire(
  redis,
  logger,
  lock_key,
  acquirer_id,
  host_id,
  access_strategy,
  timed,
  ttl_shift,
  ttl,
  queue_ttl,
  meta,
  log_sampled,
  instr_sampled,
  should_expire,
  should_decrease,
  &block
)
  initial_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)

  if block_given?
    if timed && ttl != nil
      # NOTE:
      #   - steep is ignored cuz steep can not recognize `::Integer - ::Integer|::Float`
      #     operation here for some mystical reason (it tryes to find overloadd `-` method for
      #     integer and fails on it);
      #   - so we need to ignore steep here at all and manually set the type of each
      #     variable for the correct following variable type recognitions;

      # steep:ignore:start
      # @type var ttl: Integer
      # @type var ttl_shift: Float|Integer
      # @type var timeout: Float
      timeout = ((ttl - ttl_shift) / 1_000.0).yield_self do |time|
        # @type var time: Float
        # NOTE: time in <seconds> cuz Ruby's Timeout requires <seconds>
        (time < 0) ? 0.0 : time
      end
      # steep:ignore:end

      yield_with_timeout(
        timeout,
        lock_key,
        ttl,
        acquirer_id,
        host_id,
        meta,
        &block # steep:ignore
      )
    else
      yield
    end
  end
ensure
  if should_expire # TODO: comment all cases/examples when should_expire is true
    LogVisitor.expire_lock(
      logger, log_sampled, lock_key,
      queue_ttl, acquirer_id, host_id, access_strategy
    )
    redis.call('EXPIRE', lock_key, '0')
  elsif should_decrease # TODO: comment all cases/examples when should_expire is true
    finish_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)
    # @type var initial_time: Integer
    spent_time = (finish_time - initial_time)
    # @type var ttl: Integer
    decreased_ttl = ttl - spent_time - RedisQueuedLocks::Resource::REDIS_TIMESHIFT_ERROR

    if decreased_ttl > 0
      LogVisitor.decrease_lock(
        logger, log_sampled, lock_key,
        decreased_ttl, queue_ttl, acquirer_id, host_id, access_strategy
      )
      # NOTE:# NOTE: EVAL signature -> <lua script>, (number of keys), *(keys), *(arguments)
      redis.call('EVAL', DECREASE_LOCK_PTTL, 1, lock_key, decreased_ttl)
      # TODO: upload scripts to the redis
    end
  end
end