falqon 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -1
- data/Gemfile +40 -8
- data/README.md +108 -8
- data/bin/falqon +8 -0
- data/config/inflections.rb +3 -1
- data/lib/falqon/cli/base.rb +35 -0
- data/lib/falqon/cli/clear.rb +86 -0
- data/lib/falqon/cli/delete.rb +152 -0
- data/lib/falqon/cli/kill.rb +143 -0
- data/lib/falqon/cli/list.rb +26 -0
- data/lib/falqon/cli/refill.rb +36 -0
- data/lib/falqon/cli/revive.rb +36 -0
- data/lib/falqon/cli/schedule.rb +40 -0
- data/lib/falqon/cli/show.rb +189 -0
- data/lib/falqon/cli/stats.rb +44 -0
- data/lib/falqon/cli/status.rb +47 -0
- data/lib/falqon/cli/version.rb +14 -0
- data/lib/falqon/cli.rb +168 -0
- data/lib/falqon/concerns/hooks.rb +101 -0
- data/lib/falqon/configuration.rb +141 -0
- data/lib/falqon/connection_pool_snooper.rb +15 -0
- data/lib/falqon/data.rb +11 -0
- data/lib/falqon/error.rb +13 -0
- data/lib/falqon/identifier.rb +11 -0
- data/lib/falqon/message.rb +221 -0
- data/lib/falqon/middlewares/logger.rb +32 -0
- data/lib/falqon/queue.rb +640 -0
- data/lib/falqon/strategies/linear.rb +82 -0
- data/lib/falqon/strategies/none.rb +44 -0
- data/lib/falqon/strategy.rb +26 -0
- data/lib/falqon/sub_queue.rb +96 -0
- data/lib/falqon/sub_set.rb +92 -0
- data/lib/falqon/version.rb +7 -2
- data/lib/falqon.rb +63 -0
- data/lib/generators/falqon/install.rb +37 -0
- metadata +100 -13
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
module Strategies
|
7
|
+
##
|
8
|
+
# Retry strategy that retries a fixed number of times
|
9
|
+
#
|
10
|
+
# When a message fails to process, it is moved to the scheduled queue, and retried after a fixed delay (configured by {Falqon::Queue#retry_delay}).
|
11
|
+
# If a messages fails to process after the maximum number of retries (configured by {Falqon::Queue#max_retries}), it is marked as dead, and moved to the dead subqueue.
|
12
|
+
#
|
13
|
+
# When using the linear strategy and the retry delay is set to a non-zero value, a scheduled needs to be started to retry the messages after the configured delay.
|
14
|
+
#
|
15
|
+
# queue = Falqon::Queue.new("my_queue")
|
16
|
+
#
|
17
|
+
# # Start the watcher in a separate thread
|
18
|
+
# Thread.new { loop { queue.schedule; sleep 1 } }
|
19
|
+
#
|
20
|
+
# # Or start the watcher in a separate fiber
|
21
|
+
# Fiber
|
22
|
+
# .new { loop { queue.schedule; sleep 1 } }
|
23
|
+
# .resume
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# queue = Falqon::Queue.new("my_queue", retry_strategy: :linear, retry_delay: 60, max_retries: 3)
|
27
|
+
# queue.push("Hello, World!")
|
28
|
+
# queue.pop { raise Falqon::Error }
|
29
|
+
# queue.inspect # => #<Falqon::Queue name="my_queue" pending=0 processing=0 scheduled=1 dead=0>
|
30
|
+
# sleep 60
|
31
|
+
# queue.pop # => "Hello, World!"
|
32
|
+
#
|
33
|
+
class Linear < Strategy
|
34
|
+
# @!visibility private
|
35
|
+
sig { params(message: Message, error: Error).void }
|
36
|
+
def retry(message, error)
|
37
|
+
queue.redis.with do |r|
|
38
|
+
# Increment retry count
|
39
|
+
retries = r.hincrby("#{queue.id}:metadata:#{message.id}", :retries, 1)
|
40
|
+
|
41
|
+
r.multi do |t|
|
42
|
+
# Set error metadata
|
43
|
+
t.hset(
|
44
|
+
"#{queue.id}:metadata:#{message.id}",
|
45
|
+
:retried_at, Time.now.to_i,
|
46
|
+
:retry_error, error.message,
|
47
|
+
)
|
48
|
+
|
49
|
+
if retries < queue.max_retries || queue.max_retries == -1
|
50
|
+
if queue.retry_delay.positive?
|
51
|
+
queue.logger.debug "Scheduling message #{message.id} on queue #{queue.name} in #{queue.retry_delay} seconds (attempt #{retries})"
|
52
|
+
|
53
|
+
# Add identifier to scheduled queue
|
54
|
+
queue.scheduled.add(message.id, Time.now.to_i + queue.retry_delay)
|
55
|
+
|
56
|
+
# Set message status
|
57
|
+
t.hset("#{queue.id}:metadata:#{message.id}", :status, "scheduled")
|
58
|
+
else
|
59
|
+
queue.logger.debug "Requeuing message #{message.id} on queue #{queue.name} (attempt #{retries})"
|
60
|
+
|
61
|
+
# Add identifier back to pending queue
|
62
|
+
queue.pending.add(message.id)
|
63
|
+
|
64
|
+
# Set message status
|
65
|
+
t.hset("#{queue.id}:metadata:#{message.id}", :status, "pending")
|
66
|
+
end
|
67
|
+
else
|
68
|
+
# Kill message after max retries
|
69
|
+
message.kill
|
70
|
+
|
71
|
+
# Set message status
|
72
|
+
t.hset("#{queue.id}:metadata:#{message.id}", :status, "dead")
|
73
|
+
end
|
74
|
+
|
75
|
+
# Remove identifier from processing queue
|
76
|
+
queue.processing.remove(message.id)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
module Strategies
|
7
|
+
##
|
8
|
+
# Retry strategy that does not retry
|
9
|
+
#
|
10
|
+
# When a message fails to process, it is immediately marked as dead and moved to the dead subqueue.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# queue = Falqon::Queue.new("my_queue", retry_strategy: :none)
|
14
|
+
# queue.push("Hello, World!")
|
15
|
+
# queue.pop { raise Falqon::Error }
|
16
|
+
# queue.inspect # => #<Falqon::Queue name="my_queue" pending=0 processing=0 scheduled=0 dead=1>
|
17
|
+
#
|
18
|
+
class None < Strategy
|
19
|
+
# @!visibility private
|
20
|
+
sig { params(message: Message, error: Error).void }
|
21
|
+
def retry(message, error)
|
22
|
+
queue.redis.with do |r|
|
23
|
+
r.multi do |t|
|
24
|
+
# Set error metadata
|
25
|
+
t.hset(
|
26
|
+
"#{queue.id}:metadata:#{message.id}",
|
27
|
+
:retried_at, Time.now.to_i,
|
28
|
+
:retry_error, error.message,
|
29
|
+
)
|
30
|
+
|
31
|
+
# Kill message immediately
|
32
|
+
message.kill
|
33
|
+
|
34
|
+
# Remove identifier from processing queue
|
35
|
+
queue.processing.remove(message.id)
|
36
|
+
|
37
|
+
# Set message status
|
38
|
+
t.hset("#{queue.id}:metadata:#{message.id}", :status, "dead")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
##
|
7
|
+
# Base class for retry strategies
|
8
|
+
# @!visibility private
|
9
|
+
#
|
10
|
+
class Strategy
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { returns(Queue) }
|
14
|
+
attr_reader :queue
|
15
|
+
|
16
|
+
sig { params(queue: Queue).void }
|
17
|
+
def initialize(queue)
|
18
|
+
@queue = queue
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { params(message: Message, error: Error).void }
|
22
|
+
def retry(message, error)
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
##
|
7
|
+
# Simple queue abstraction on top of Redis
|
8
|
+
# @!visibility private
|
9
|
+
#
|
10
|
+
class SubQueue
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { returns(String) }
|
14
|
+
attr_reader :type
|
15
|
+
|
16
|
+
sig { returns(String) }
|
17
|
+
attr_reader :id
|
18
|
+
|
19
|
+
sig { returns(Queue) }
|
20
|
+
attr_reader :queue
|
21
|
+
|
22
|
+
sig { params(queue: Queue, type: T.nilable(String)).void }
|
23
|
+
def initialize(queue, type = nil)
|
24
|
+
@type = type || "pending"
|
25
|
+
@id = [queue.id, type].compact.join(":")
|
26
|
+
@queue = queue
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { params(message_id: Identifier, head: T.nilable(T::Boolean)).void }
|
30
|
+
def add(message_id, head: false)
|
31
|
+
queue.redis.with do |r|
|
32
|
+
if head
|
33
|
+
r.lpush(id, message_id)
|
34
|
+
else
|
35
|
+
r.rpush(id, message_id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { params(message_id: Identifier).void }
|
41
|
+
def remove(message_id)
|
42
|
+
queue.redis.with do |r|
|
43
|
+
r.lrem(id, 0, message_id)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(index: Integer).returns(T.nilable(Identifier)) }
|
48
|
+
def peek(index: 0)
|
49
|
+
queue.redis.with do |r|
|
50
|
+
r.lindex(id, index)&.to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { params(start: Integer, stop: Integer).returns(T::Array[Identifier]) }
|
55
|
+
def range(start: 0, stop: -1)
|
56
|
+
queue.redis.with do |r|
|
57
|
+
r.lrange(id, start, stop).map(&:to_i)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
sig { returns(T::Array[Identifier]) }
|
62
|
+
def clear
|
63
|
+
queue.redis.with do |r|
|
64
|
+
# Get all identifiers from queue
|
65
|
+
message_ids = r.lrange(id, 0, -1)
|
66
|
+
|
67
|
+
# Delete all data and clear queue
|
68
|
+
# TODO: clear data in batches
|
69
|
+
r.del(*message_ids.flat_map { |message_id| ["#{queue.id}:data:#{message_id}", "#{queue.id}:metadata:#{message_id}"] }, id, "#{queue.id}:id")
|
70
|
+
|
71
|
+
# Return identifiers
|
72
|
+
message_ids.map(&:to_i)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
sig { returns(Integer) }
|
77
|
+
def size
|
78
|
+
queue.redis.with { |r| r.llen(id) }
|
79
|
+
end
|
80
|
+
|
81
|
+
sig { returns(T::Boolean) }
|
82
|
+
def empty?
|
83
|
+
size.zero?
|
84
|
+
end
|
85
|
+
|
86
|
+
sig { returns(T::Array[Identifier]) }
|
87
|
+
def to_a
|
88
|
+
queue.redis.with { |r| r.lrange(id, 0, -1).map(&:to_i) }
|
89
|
+
end
|
90
|
+
|
91
|
+
sig { returns(String) }
|
92
|
+
def inspect
|
93
|
+
"#<#{self.class} name=#{type} size=#{size}>"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
##
|
7
|
+
# Simple sorted set abstraction on top of Redis
|
8
|
+
# @!visibility private
|
9
|
+
#
|
10
|
+
class SubSet
|
11
|
+
extend T::Sig
|
12
|
+
|
13
|
+
sig { returns(String) }
|
14
|
+
attr_reader :type
|
15
|
+
|
16
|
+
sig { returns(String) }
|
17
|
+
attr_reader :id
|
18
|
+
|
19
|
+
sig { returns(Queue) }
|
20
|
+
attr_reader :queue
|
21
|
+
|
22
|
+
sig { params(queue: Queue, type: T.nilable(String)).void }
|
23
|
+
def initialize(queue, type = nil)
|
24
|
+
@type = type || "pending"
|
25
|
+
@id = [queue.id, type].compact.join(":")
|
26
|
+
@queue = queue
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { params(message_id: Identifier, score: Integer).void }
|
30
|
+
def add(message_id, score)
|
31
|
+
queue.redis.with do |r|
|
32
|
+
r.zadd(id, score, message_id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(message_id: Identifier).void }
|
37
|
+
def remove(message_id)
|
38
|
+
queue.redis.with do |r|
|
39
|
+
r.zrem(id, message_id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { params(index: Integer).returns(T.nilable(Identifier)) }
|
44
|
+
def peek(index: 0)
|
45
|
+
queue.redis.with do |r|
|
46
|
+
r.zrange(id, index, index).first&.to_i
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
sig { params(start: Integer, stop: Integer).returns(T::Array[Identifier]) }
|
51
|
+
def range(start: 0, stop: -1)
|
52
|
+
queue.redis.with do |r|
|
53
|
+
r.zrange(id, start, stop).map(&:to_i)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
sig { returns(T::Array[Identifier]) }
|
58
|
+
def clear
|
59
|
+
queue.redis.with do |r|
|
60
|
+
# Get all identifiers from queue
|
61
|
+
# TODO: work in batches
|
62
|
+
message_ids = r.zrange(id, 0, -1)
|
63
|
+
|
64
|
+
# Delete all data and clear queue
|
65
|
+
r.del(*message_ids.flat_map { |message_id| ["#{queue.id}:data:#{message_id}", "#{queue.id}:metadata:#{message_id}"] }, id, "#{queue.id}:id")
|
66
|
+
|
67
|
+
# Return identifiers
|
68
|
+
message_ids.map(&:to_i)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { returns(Integer) }
|
73
|
+
def size
|
74
|
+
queue.redis.with { |r| r.zcount(id, "-inf", "+inf") }
|
75
|
+
end
|
76
|
+
|
77
|
+
sig { returns(T::Boolean) }
|
78
|
+
def empty?
|
79
|
+
size.zero?
|
80
|
+
end
|
81
|
+
|
82
|
+
sig { returns(T::Array[Identifier]) }
|
83
|
+
def to_a
|
84
|
+
queue.redis.with { |r| r.zrange(id, 0, -1).map(&:to_i) }
|
85
|
+
end
|
86
|
+
|
87
|
+
sig { returns(String) }
|
88
|
+
def inspect
|
89
|
+
"#<#{self.class} name=#{type} size=#{size}>"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/falqon/version.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Falqon
|
4
|
+
# @!visibility private
|
4
5
|
module Version
|
5
|
-
MAJOR =
|
6
|
+
MAJOR = 1
|
6
7
|
MINOR = 0
|
7
|
-
PATCH =
|
8
|
+
PATCH = 0
|
8
9
|
PRE = nil
|
9
10
|
|
10
11
|
VERSION = [MAJOR, MINOR, PATCH].compact.join(".")
|
@@ -12,5 +13,9 @@ module Falqon
|
|
12
13
|
STRING = [VERSION, PRE].compact.join("-")
|
13
14
|
end
|
14
15
|
|
16
|
+
# @!visibility private
|
15
17
|
VERSION = Version::STRING
|
18
|
+
|
19
|
+
# @!visibility private
|
20
|
+
PROTOCOL = 1
|
16
21
|
end
|
data/lib/falqon.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# typed: true
|
4
|
+
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
require "sorbet-runtime"
|
8
|
+
require "zeitwerk"
|
9
|
+
|
10
|
+
module Falqon
|
11
|
+
class << self
|
12
|
+
extend Forwardable
|
13
|
+
extend T::Sig
|
14
|
+
|
15
|
+
# Code loader instance
|
16
|
+
# @!visibility private
|
17
|
+
attr_reader :loader
|
18
|
+
|
19
|
+
# Global configuration
|
20
|
+
#
|
21
|
+
# @see Falqon::Configuration
|
22
|
+
sig { returns(Configuration) }
|
23
|
+
def configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!visibility private
|
28
|
+
def root
|
29
|
+
@root ||= Pathname.new(File.expand_path(File.join("..", ".."), __FILE__))
|
30
|
+
end
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
def setup
|
34
|
+
@loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
35
|
+
|
36
|
+
# Register inflections
|
37
|
+
require root.join("config/inflections.rb")
|
38
|
+
|
39
|
+
# Collapse concerns directory
|
40
|
+
loader.collapse(root.join("lib/falqon/concerns"))
|
41
|
+
|
42
|
+
# Configure Rails generators (if applicable)
|
43
|
+
if const_defined?(:Rails)
|
44
|
+
loader.collapse(root.join("lib/generators"))
|
45
|
+
else
|
46
|
+
loader.ignore(root.join("lib/generators"))
|
47
|
+
end
|
48
|
+
|
49
|
+
loader.setup
|
50
|
+
loader.eager_load
|
51
|
+
end
|
52
|
+
|
53
|
+
# @!visibility private
|
54
|
+
def configure
|
55
|
+
yield configuration
|
56
|
+
end
|
57
|
+
|
58
|
+
def_delegator :configuration, :redis
|
59
|
+
def_delegator :configuration, :logger
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Falqon.setup
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
module Falqon
|
6
|
+
# @!visibility private
|
7
|
+
class Install < Rails::Generators::Base
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def create_initializer_file
|
11
|
+
create_file "config/initializers/falqon.rb", <<~RUBY
|
12
|
+
Falqon.configure do |config|
|
13
|
+
# Configure global queue name prefix
|
14
|
+
# config.prefix = ENV.fetch("FALQON_PREFIX", "falqon")
|
15
|
+
|
16
|
+
# Retry strategy (none or linear)
|
17
|
+
# config.retry_strategy = :linear
|
18
|
+
|
19
|
+
# Maximum number of retries before a message is discarded (-1 for infinite retries)
|
20
|
+
# config.max_retries = 3
|
21
|
+
|
22
|
+
# Retry delay (in seconds) for linear retry strategy (defaults to 0)
|
23
|
+
# config.retry_delay = 60
|
24
|
+
|
25
|
+
# Configure the Redis client options
|
26
|
+
# config.redis_options = { url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0") }
|
27
|
+
|
28
|
+
# Or, configure the Redis client directly
|
29
|
+
# config.redis = ConnectionPool.new(size: 5, timeout: 5) { Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/0")) }
|
30
|
+
|
31
|
+
# Configure logger
|
32
|
+
# config.logger = Logger.new(STDOUT)
|
33
|
+
end
|
34
|
+
RUBY
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,33 +1,90 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: falqon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Dejonckheere
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: connection_pool
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sorbet-runtime
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.5'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
13
69
|
- !ruby/object:Gem::Dependency
|
14
70
|
name: zeitwerk
|
15
71
|
requirement: !ruby/object:Gem::Requirement
|
16
72
|
requirements:
|
17
|
-
- - "
|
73
|
+
- - "~>"
|
18
74
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
75
|
+
version: '2.6'
|
20
76
|
type: :runtime
|
21
77
|
prerelease: false
|
22
78
|
version_requirements: !ruby/object:Gem::Requirement
|
23
79
|
requirements:
|
24
|
-
- - "
|
80
|
+
- - "~>"
|
25
81
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
27
|
-
description: Simple, efficient messaging queue for Ruby
|
82
|
+
version: '2.6'
|
83
|
+
description: Simple, efficient, and reliable messaging queue for Ruby
|
28
84
|
email:
|
29
85
|
- florian@floriandejonckheere.be
|
30
|
-
executables:
|
86
|
+
executables:
|
87
|
+
- falqon
|
31
88
|
extensions: []
|
32
89
|
extra_rdoc_files: []
|
33
90
|
files:
|
@@ -35,15 +92,45 @@ files:
|
|
35
92
|
- Gemfile
|
36
93
|
- LICENSE.md
|
37
94
|
- README.md
|
95
|
+
- bin/falqon
|
38
96
|
- config/inflections.rb
|
97
|
+
- lib/falqon.rb
|
98
|
+
- lib/falqon/cli.rb
|
99
|
+
- lib/falqon/cli/base.rb
|
100
|
+
- lib/falqon/cli/clear.rb
|
101
|
+
- lib/falqon/cli/delete.rb
|
102
|
+
- lib/falqon/cli/kill.rb
|
103
|
+
- lib/falqon/cli/list.rb
|
104
|
+
- lib/falqon/cli/refill.rb
|
105
|
+
- lib/falqon/cli/revive.rb
|
106
|
+
- lib/falqon/cli/schedule.rb
|
107
|
+
- lib/falqon/cli/show.rb
|
108
|
+
- lib/falqon/cli/stats.rb
|
109
|
+
- lib/falqon/cli/status.rb
|
110
|
+
- lib/falqon/cli/version.rb
|
111
|
+
- lib/falqon/concerns/hooks.rb
|
112
|
+
- lib/falqon/configuration.rb
|
113
|
+
- lib/falqon/connection_pool_snooper.rb
|
114
|
+
- lib/falqon/data.rb
|
115
|
+
- lib/falqon/error.rb
|
116
|
+
- lib/falqon/identifier.rb
|
117
|
+
- lib/falqon/message.rb
|
118
|
+
- lib/falqon/middlewares/logger.rb
|
119
|
+
- lib/falqon/queue.rb
|
120
|
+
- lib/falqon/strategies/linear.rb
|
121
|
+
- lib/falqon/strategies/none.rb
|
122
|
+
- lib/falqon/strategy.rb
|
123
|
+
- lib/falqon/sub_queue.rb
|
124
|
+
- lib/falqon/sub_set.rb
|
39
125
|
- lib/falqon/version.rb
|
126
|
+
- lib/generators/falqon/install.rb
|
40
127
|
homepage: https://github.com/floriandejonckheere/falqon
|
41
128
|
licenses:
|
42
129
|
- LGPL-3.0
|
43
130
|
metadata:
|
44
131
|
source_code_uri: https://github.com/floriandejonckheere/falqon.git
|
45
132
|
rubygems_mfa_required: 'true'
|
46
|
-
post_install_message:
|
133
|
+
post_install_message:
|
47
134
|
rdoc_options: []
|
48
135
|
require_paths:
|
49
136
|
- lib
|
@@ -51,15 +138,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
138
|
requirements:
|
52
139
|
- - ">="
|
53
140
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
141
|
+
version: '3.1'
|
55
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
143
|
requirements:
|
57
144
|
- - ">="
|
58
145
|
- !ruby/object:Gem::Version
|
59
146
|
version: '0'
|
60
147
|
requirements: []
|
61
|
-
rubygems_version: 3.
|
62
|
-
signing_key:
|
148
|
+
rubygems_version: 3.4.20
|
149
|
+
signing_key:
|
63
150
|
specification_version: 4
|
64
151
|
summary: Simple messaging queue
|
65
152
|
test_files: []
|