falqon 0.1.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 315b92a750d6358553f6b0a46623c016f871e556eb9c787fe154454cd426ef56
4
- data.tar.gz: c0fda1f5f23662c9c0ff2316bdf976fec620fb3f4b8a3be29c79fd65b5da5ac9
3
+ metadata.gz: 5ac7a29b42908bf546c1ef179712b24d4c29cdc41f268172ae94efc01f2e28a5
4
+ data.tar.gz: 89c27514ea3ecd84fd191e20696a251c8a304d5149f4276007dc815181cb7bd8
5
5
  SHA512:
6
- metadata.gz: 2205cb5ebf976ee5a61b33dd8157619d27ae6d2d0f2f8eca5d93fbf52b2e6719d38d697218525bfab105ec7db6fd496f70a681587a2eb4da6677e10b20a170a4
7
- data.tar.gz: d460ebf86b84a2814f41cdb94f134f28eafcebaab3d7ec9bf90fe11d1b8329f739ae7a17c4b40c07c69834c393fad1db79997602ae45b8a1637aa4b2838d451a
6
+ metadata.gz: 94b591a05d679e6df6b1308adcebb2619a30923ce4a5c2168f5dd07d381737b59ee6ed8ff4883d8913ab8d07c1a516ec32021cedf068c023f127d81394685c9e
7
+ data.tar.gz: a83d8fc3f97b8bbbc7c399fd3e7674986470d3fe07fe6384d2605a5510378a1bdddf93f0ac2ad7622ecb1db4018916bd05a91e3e96e362ebc1a93fa1395c67e1
data/CHANGELOG.md CHANGED
@@ -1,13 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## Falqon v0.1.0 (2024-11-16)
4
-
5
- Initial release
6
-
7
- ## Falqon v0.0.1 (2023-06-22)
8
-
9
- # Changelog
10
-
11
3
  All notable changes to this project will be documented in this file.
12
4
 
13
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
@@ -21,5 +13,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
13
 
22
14
  ### Removed
23
15
 
24
- [unreleased]: https://github.com/floriandejonckheere/falqon/compare/v0.1.0...HEAD
25
- [0.1.0]: https://github.com/floriandejonckheere/falqon/compare/v0.0.1...v0.1.0
16
+ ## Falqon v1.1.0 (2025-05-18)
17
+
18
+ ### Changed
19
+
20
+ - Rewrite `Falqon::Queue.all` to return queues alphabetically by name
21
+
22
+ ### Removed
23
+
24
+ - Remove support for Ruby 3.1
25
+
26
+ ## Falqon v1.0.0 (2024-12-07)
27
+
28
+ ### Changed
29
+
30
+ - Use atomic execution (MULTI/EXEC) where possible.
31
+
32
+ ## Falqon v0.1.0 (2024-11-16)
33
+
34
+ Initial release
35
+
36
+ ## Falqon v0.0.1 (2023-06-22)
37
+
38
+ [unreleased]: https://github.com/floriandejonckheere/falqon/compare/v1.1.0...HEAD
39
+ [1.1.0]: https://github.com/floriandejonckheere/falqon-pro/releases/tag/v1.1.0
40
+ [1.0.0]: https://github.com/floriandejonckheere/falqon-pro/releases/tag/v1.0.0
41
+ [0.1.0]: https://github.com/floriandejonckheere/falqon-pro/releases/tag/v0.1.0
data/Gemfile CHANGED
@@ -14,35 +14,35 @@ group :development do
14
14
  gem "yard-sorbet", "0.9.0", require: false
15
15
 
16
16
  # Simple server
17
- gem "webrick", "1.8.2", require: false
17
+ gem "webrick", "1.9.1", require: false
18
18
  end
19
19
 
20
20
  group :development, :test do
21
21
  # Debugger
22
- gem "debug", "1.9.2", require: false
22
+ gem "debug", "1.10.0", require: false
23
23
 
24
24
  # Build objects for tests
25
- gem "factory_bot", "6.5.0", require: false
25
+ gem "factory_bot", "6.5.1", require: false
26
26
 
27
27
  # Generate fake data
28
- gem "ffaker", "2.23.0", require: false
28
+ gem "ffaker", "2.24.0", require: false
29
29
 
30
30
  # Mock Redis server
31
- gem "mock_redis", "0.45.0", require: false
31
+ gem "mock_redis", "0.49.0", require: false
32
32
 
33
33
  # Behavior-driven test framework
34
34
  gem "rspec", "3.13.0", require: false
35
35
 
36
36
  # Linter
37
- gem "rubocop", "1.68.0", require: false
38
- gem "rubocop-factory_bot", "2.26.1", require: false
39
- gem "rubocop-performance", "1.22.1", require: false
40
- gem "rubocop-rake", "0.6.0", require: false
41
- gem "rubocop-rspec", "3.2.0", require: false
37
+ gem "rubocop", "1.75.6", require: false
38
+ gem "rubocop-factory_bot", "2.27.1", require: false
39
+ gem "rubocop-performance", "1.25.0", require: false
40
+ gem "rubocop-rake", "0.7.1", require: false
41
+ gem "rubocop-rspec", "3.6.0", require: false
42
42
 
43
43
  # Type checker
44
- gem "sorbet", "0.5.11645", require: false
45
- gem "tapioca", "0.16.4", require: false
44
+ gem "sorbet", "0.5.12115", require: false
45
+ gem "tapioca", "0.16.11", require: false
46
46
 
47
47
  # Time control
48
48
  gem "timecop", "0.9.10", require: false
data/README.md CHANGED
@@ -23,8 +23,9 @@ Falqon offers an elegant solution for messaging queues in Ruby.
23
23
 
24
24
  - Install Falqon and get working with messaging queues in a heartbeat using the [quickstart guide](#quickstart)
25
25
  - Check out the [API documentation](https://docs.falqon.dev/) for more information on how to use Falqon in your application
26
- - Check out the CLI documentation](https://docs.falqon.dev/) for more information on how to manage queues and messages from the command line
26
+ - Check out the [CLI documentation](https://docs.falqon.dev/Falqon/CLI.html) for more information on how to manage queues and messages from the command line
27
27
  - Read the [architecture documentation](#architecture) to learn more about how Falqon works under the hood
28
+ - Read about [Falqon Pro](https://docs.falqon.dev/pro), the commercial addon for Falqon that offers additional features
28
29
 
29
30
  ## Quickstart
30
31
 
@@ -52,7 +53,7 @@ Or install it yourself as:
52
53
  ### Configuration
53
54
 
54
55
  The default configuration works out of the box with the provided `docker-compose.yml` file.
55
- See [configuration](#configuration) if you want to adjust the configuration.
56
+ See [configuration](https://docs.falqon.dev/Falqon/Configuration.html) if you want to adjust the configuration.
56
57
 
57
58
  ### Usage
58
59
 
@@ -134,7 +135,7 @@ The documentation in `docs/` is automatically built by [YARD](https://yardoc.org
134
135
  Locally, you can build the documentation using the following commands:
135
136
 
136
137
  ```sh
137
- rake yrad
138
+ rake yard
138
139
  ```
139
140
 
140
141
  In development, you can start a local server to preview the documentation:
@@ -44,7 +44,7 @@ module Falqon
44
44
  extend T::Sig
45
45
 
46
46
  # @!visibility private
47
- sig { params(base: T.class_of(Hooks)).void }
47
+ sig { params(base: Class).void }
48
48
  def self.included(base)
49
49
  base.extend(ClassMethods)
50
50
  end
@@ -101,13 +101,17 @@ module Falqon
101
101
  sig { returns(Message) }
102
102
  def create
103
103
  redis.with do |r|
104
- # Store data
105
- r.set("#{queue.id}:data:#{id}", data)
104
+ message_id = id
106
105
 
107
- # Set metadata
108
- r.hset("#{queue.id}:metadata:#{id}",
109
- :created_at, Time.now.to_i,
110
- :updated_at, Time.now.to_i,)
106
+ r.multi do |t|
107
+ # Store data
108
+ t.set("#{queue.id}:data:#{message_id}", data)
109
+
110
+ # Set metadata
111
+ t.hset("#{queue.id}:metadata:#{message_id}",
112
+ :created_at, Time.now.to_i,
113
+ :updated_at, Time.now.to_i,)
114
+ end
111
115
  end
112
116
 
113
117
  self
@@ -141,12 +145,14 @@ module Falqon
141
145
  sig { void }
142
146
  def delete
143
147
  redis.with do |r|
144
- # Delete message from queue
145
- queue.pending.remove(id)
146
- queue.dead.remove(id)
147
-
148
- # Delete data and metadata
149
- r.del("#{queue.id}:data:#{id}", "#{queue.id}:metadata:#{id}")
148
+ r.multi do |t|
149
+ # Delete message from queue
150
+ queue.pending.remove(id)
151
+ queue.dead.remove(id)
152
+
153
+ # Delete data and metadata
154
+ t.del("#{queue.id}:data:#{id}", "#{queue.id}:metadata:#{id}")
155
+ end
150
156
  end
151
157
  end
152
158
 
@@ -156,9 +162,7 @@ module Falqon
156
162
  #
157
163
  sig { returns Integer }
158
164
  def size
159
- redis.with do |r|
160
- r.strlen("#{queue.id}:data:#{id}")
161
- end
165
+ redis.with { |r| r.strlen("#{queue.id}:data:#{id}") }
162
166
  end
163
167
 
164
168
  # Metadata of the message
@@ -183,7 +187,7 @@ module Falqon
183
187
  def_delegator :queue, :logger
184
188
 
185
189
  ##
186
- # Metadata for an message
190
+ # Metadata for a message
187
191
  #
188
192
  class Metadata < T::Struct
189
193
  # Status (unknown, pending, processing, scheduled, dead)
@@ -209,11 +213,8 @@ module Falqon
209
213
  # @!visibility private
210
214
  #
211
215
  def self.parse(data)
212
- # Keys that are not numeric
213
- keys = ["status", "retry_error"]
214
-
215
216
  # Transform keys to symbols, and values to integers
216
- new(data.to_h { |k, v| [k.to_sym, keys.include?(k) ? v : v.to_i] })
217
+ new(data.to_h { |k, v| [k.to_sym, (send(props.dig(k.to_sym, :type).name.to_sym, v) if v)] })
217
218
  end
218
219
  end
219
220
  end
data/lib/falqon/queue.rb CHANGED
@@ -91,15 +91,17 @@ module Falqon
91
91
 
92
92
  raise Falqon::VersionMismatchError, "Queue #{name} is using protocol version #{queue_version}, but this client is using protocol version #{version}" if queue_version && queue_version.to_i != @version
93
93
 
94
- # Register the queue
95
- r.sadd([Falqon.configuration.prefix, "queues"].compact.join(":"), name)
94
+ r.multi do |t|
95
+ # Register the queue
96
+ t.sadd([Falqon.configuration.prefix, "queues"].compact.join(":"), name)
96
97
 
97
- # Set creation and update timestamp (if not set)
98
- r.hsetnx("#{id}:metadata", :created_at, Time.now.to_i)
99
- r.hsetnx("#{id}:metadata", :updated_at, Time.now.to_i)
98
+ # Set creation and update timestamp (if not set)
99
+ t.hsetnx("#{id}:metadata", :created_at, Time.now.to_i)
100
+ t.hsetnx("#{id}:metadata", :updated_at, Time.now.to_i)
100
101
 
101
- # Set protocol version
102
- r.hsetnx("#{id}:metadata", :version, @version)
102
+ # Set protocol version
103
+ t.hsetnx("#{id}:metadata", :version, @version)
104
+ end
103
105
  end
104
106
 
105
107
  run_hook :initialize, :after
@@ -185,18 +187,23 @@ module Falqon
185
187
  # Move identifier from pending queue to processing queue
186
188
  message_id = r.blmove(pending.id, processing.id, :left, :right).to_i
187
189
 
188
- # Set message status
189
- r.hset("#{id}:metadata:#{message_id}", :status, "processing")
190
+ # Get retry count
191
+ retries = r.hget("#{id}:metadata:#{message_id}", :retries).to_i
190
192
 
191
- # Set update timestamp
192
- r.hset("#{id}:metadata", :updated_at, Time.now.to_i)
193
- r.hset("#{id}:metadata:#{message_id}", :updated_at, Time.now.to_i)
193
+ r.multi do |t|
194
+ # Set message status
195
+ t.hset("#{id}:metadata:#{message_id}", :status, "processing")
194
196
 
195
- # Increment processing counter
196
- r.hincrby("#{id}:metadata", :processed, 1)
197
+ # Set update timestamp
198
+ t.hset("#{id}:metadata", :updated_at, Time.now.to_i)
199
+ t.hset("#{id}:metadata:#{message_id}", :updated_at, Time.now.to_i)
197
200
 
198
- # Increment retry counter if message is retried
199
- r.hincrby("#{id}:metadata", :retried, 1) if r.hget("#{id}:metadata:#{message_id}", :retries).to_i.positive?
201
+ # Increment processing counter
202
+ t.hincrby("#{id}:metadata", :processed, 1)
203
+
204
+ # Increment retry counter if message is retried
205
+ t.hincrby("#{id}:metadata", :retried, 1) if retries.positive?
206
+ end
200
207
 
201
208
  Message.new(self, id: message_id)
202
209
  end
@@ -318,11 +325,13 @@ module Falqon
318
325
  message_ids = pending.clear + processing.clear + scheduled.clear + dead.clear
319
326
 
320
327
  redis.with do |r|
321
- # Clear metadata
322
- r.hdel("#{id}:metadata", :processed, :failed, :retried)
328
+ r.multi do |t|
329
+ # Clear metadata
330
+ t.hdel("#{id}:metadata", :processed, :failed, :retried)
323
331
 
324
- # Set update timestamp
325
- r.hset("#{id}:metadata", :updated_at, Time.now.to_i)
332
+ # Set update timestamp
333
+ t.hset("#{id}:metadata", :updated_at, Time.now.to_i)
334
+ end
326
335
  end
327
336
 
328
337
  run_hook :clear, :after
@@ -351,11 +360,13 @@ module Falqon
351
360
  .each(&:clear)
352
361
 
353
362
  redis.with do |r|
354
- # Delete metadata
355
- r.del("#{id}:metadata")
363
+ r.multi do |t|
364
+ # Delete metadata
365
+ t.del("#{id}:metadata")
356
366
 
357
- # Deregister the queue
358
- r.srem([Falqon.configuration.prefix, "queues"].compact.join(":"), name)
367
+ # Deregister the queue
368
+ t.srem([Falqon.configuration.prefix, "queues"].compact.join(":"), name)
369
+ end
359
370
  end
360
371
 
361
372
  run_hook :delete, :after
@@ -461,19 +472,22 @@ module Falqon
461
472
  redis.with do |r|
462
473
  # Select all identifiers that are due (score <= current timestamp)
463
474
  # FIXME: replace with zrange(by_score: true) when https://github.com/sds/mock_redis/issues/307 is resolved
475
+ # TODO: work in batches
464
476
  message_ids = r.zrangebyscore(scheduled.id, 0, Time.now.to_i).map(&:to_i)
465
477
 
466
478
  logger.debug "Scheduling messages #{message_ids.join(', ')} on queue #{name}"
467
479
 
468
- message_ids.each do |message_id|
469
- # Set message status
470
- r.hset("#{id}:metadata:#{message_id}", :status, "pending")
480
+ r.multi do |t|
481
+ message_ids.each do |message_id|
482
+ # Set message status
483
+ t.hset("#{id}:metadata:#{message_id}", :status, "pending")
471
484
 
472
- # Add identifier to pending queue
473
- pending.add(message_id)
485
+ # Add identifier to pending queue
486
+ pending.add(message_id)
474
487
 
475
- # Remove identifier from scheduled queue
476
- scheduled.remove(message_id)
488
+ # Remove identifier from scheduled queue
489
+ scheduled.remove(message_id)
490
+ end
477
491
  end
478
492
  end
479
493
 
@@ -572,6 +586,7 @@ module Falqon
572
586
  Falqon.configuration.redis.with do |r|
573
587
  r
574
588
  .smembers([Falqon.configuration.prefix, "queues"].compact.join(":"))
589
+ .sort
575
590
  .map { |id| new(id) }
576
591
  end
577
592
  end
@@ -38,14 +38,14 @@ module Falqon
38
38
  # Increment retry count
39
39
  retries = r.hincrby("#{queue.id}:metadata:#{message.id}", :retries, 1)
40
40
 
41
- # Set error metadata
42
- r.hset(
43
- "#{queue.id}:metadata:#{message.id}",
44
- :retried_at, Time.now.to_i,
45
- :retry_error, error.message,
46
- )
47
-
48
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
49
  if retries < queue.max_retries || queue.max_retries == -1
50
50
  if queue.retry_delay.positive?
51
51
  queue.logger.debug "Scheduling message #{message.id} on queue #{queue.name} in #{queue.retry_delay} seconds (attempt #{retries})"
@@ -20,14 +20,14 @@ module Falqon
20
20
  sig { params(message: Message, error: Error).void }
21
21
  def retry(message, error)
22
22
  queue.redis.with do |r|
23
- # Set error metadata
24
- r.hset(
25
- "#{queue.id}:metadata:#{message.id}",
26
- :retried_at, Time.now.to_i,
27
- :retry_error, error.message,
28
- )
29
-
30
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
31
  # Kill message immediately
32
32
  message.kill
33
33
 
@@ -65,6 +65,7 @@ module Falqon
65
65
  message_ids = r.lrange(id, 0, -1)
66
66
 
67
67
  # Delete all data and clear queue
68
+ # TODO: clear data in batches
68
69
  r.del(*message_ids.flat_map { |message_id| ["#{queue.id}:data:#{message_id}", "#{queue.id}:metadata:#{message_id}"] }, id, "#{queue.id}:id")
69
70
 
70
71
  # Return identifiers
@@ -58,6 +58,7 @@ module Falqon
58
58
  def clear
59
59
  queue.redis.with do |r|
60
60
  # Get all identifiers from queue
61
+ # TODO: work in batches
61
62
  message_ids = r.zrange(id, 0, -1)
62
63
 
63
64
  # Delete all data and clear queue
@@ -3,7 +3,7 @@
3
3
  module Falqon
4
4
  # @!visibility private
5
5
  module Version
6
- MAJOR = 0
6
+ MAJOR = 1
7
7
  MINOR = 1
8
8
  PATCH = 0
9
9
  PRE = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: falqon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.1.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: 2024-11-16 00:00:00.000000000 Z
11
+ date: 2025-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.4'
19
+ version: '2.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.4'
26
+ version: '2.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '5.0'
33
+ version: '5.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '5.0'
40
+ version: '5.4'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sorbet-runtime
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.6'
75
+ version: '2.7'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.6'
82
+ version: '2.7'
83
83
  description: Simple, efficient, and reliable messaging queue for Ruby
84
84
  email:
85
85
  - florian@floriandejonckheere.be
@@ -130,7 +130,7 @@ licenses:
130
130
  metadata:
131
131
  source_code_uri: https://github.com/floriandejonckheere/falqon.git
132
132
  rubygems_mfa_required: 'true'
133
- post_install_message:
133
+ post_install_message:
134
134
  rdoc_options: []
135
135
  require_paths:
136
136
  - lib
@@ -138,15 +138,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
138
  requirements:
139
139
  - - ">="
140
140
  - !ruby/object:Gem::Version
141
- version: '3.1'
141
+ version: '3.2'
142
142
  required_rubygems_version: !ruby/object:Gem::Requirement
143
143
  requirements:
144
144
  - - ">="
145
145
  - !ruby/object:Gem::Version
146
146
  version: '0'
147
147
  requirements: []
148
- rubygems_version: 3.3.5
149
- signing_key:
148
+ rubygems_version: 3.4.20
149
+ signing_key:
150
150
  specification_version: 4
151
151
  summary: Simple messaging queue
152
152
  test_files: []