Class: Specbandit::RedisQueue

Inherits:
Object
  • Object
show all
Defined in:
lib/specbandit/redis_queue.rb

Constant Summary collapse

MAX_ATTEMPTS =
3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(redis_url: Specbandit.configuration.redis_url) ⇒ RedisQueue

Returns a new instance of RedisQueue.



9
10
11
# File 'lib/specbandit/redis_queue.rb', line 9

def initialize(redis_url: Specbandit.configuration.redis_url)
  @redis = Redis.new(url: redis_url)
end

Instance Attribute Details

#redisObject (readonly)

Returns the value of attribute redis.



7
8
9
# File 'lib/specbandit/redis_queue.rb', line 7

def redis
  @redis
end

Instance Method Details

#closeObject



75
76
77
# File 'lib/specbandit/redis_queue.rb', line 75

def close
  redis.close
end

#length(key) ⇒ Object

Returns the current length of the queue.



44
45
46
# File 'lib/specbandit/redis_queue.rb', line 44

def length(key)
  with_retries { redis.llen(key) }
end

#mark_published(key, ttl: nil) ⇒ Object

Mark a queue key as "published" by setting a companion marker key.

The marker is a separate string key (<key>:published) that survives the queue list being fully drained. It is the source of truth for "was work ever pushed for this key?" -- Redis auto-deletes empty lists, so the list alone cannot distinguish "never pushed" from "drained".



54
55
56
57
58
59
60
61
62
# File 'lib/specbandit/redis_queue.rb', line 54

def mark_published(key, ttl: nil)
  with_retries do
    if ttl
      redis.set(published_marker(key), '1', ex: ttl)
    else
      redis.set(published_marker(key), '1')
    end
  end
end

#published?(key) ⇒ Boolean

Whether a queue key has been published (its marker exists).

Returns:

  • (Boolean)


65
66
67
# File 'lib/specbandit/redis_queue.rb', line 65

def published?(key)
  with_retries { redis.exists?(published_marker(key)) }
end

#push(key, files, ttl: nil) ⇒ Object

Push file paths onto the queue and set an expiry on the key. Returns the new length of the list.



17
18
19
20
21
22
23
24
25
# File 'lib/specbandit/redis_queue.rb', line 17

def push(key, files, ttl: nil)
  return 0 if files.empty?

  with_retries do
    count = redis.rpush(key, files)
    redis.expire(key, ttl) if ttl
    count
  end
end

#read_all(key) ⇒ Object

Read all file paths from the list non-destructively. Returns an array of file paths (empty array when key doesn't exist).



71
72
73
# File 'lib/specbandit/redis_queue.rb', line 71

def read_all(key)
  with_retries { redis.lrange(key, 0, -1) }
end

#steal(key, count) ⇒ Object

Atomically steal up to count file paths from the queue. Returns an array of file paths (empty array when exhausted).

Uses LPOP with count argument (Redis 6.2+).



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/specbandit/redis_queue.rb', line 31

def steal(key, count)
  result = with_retries { redis.lpop(key, count) }

  # LPOP returns nil when the key doesn't exist or list is empty,
  # and returns a single string (not array) when count is 1 on some versions.
  case result
  when nil then []
  when String then [result]
  else Array(result)
  end
end