falqon 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 315b92a750d6358553f6b0a46623c016f871e556eb9c787fe154454cd426ef56
4
- data.tar.gz: c0fda1f5f23662c9c0ff2316bdf976fec620fb3f4b8a3be29c79fd65b5da5ac9
3
+ metadata.gz: 2a6de2c2359a6d2aebf3f7f0531b9dea885d46f579a64aa0b46036c204c7df52
4
+ data.tar.gz: 8896a1d994cd209f436c8c260c5eba7985c9b3055064f186e26d7ff8452f7407
5
5
  SHA512:
6
- metadata.gz: 2205cb5ebf976ee5a61b33dd8157619d27ae6d2d0f2f8eca5d93fbf52b2e6719d38d697218525bfab105ec7db6fd496f70a681587a2eb4da6677e10b20a170a4
7
- data.tar.gz: d460ebf86b84a2814f41cdb94f134f28eafcebaab3d7ec9bf90fe11d1b8329f739ae7a17c4b40c07c69834c393fad1db79997602ae45b8a1637aa4b2838d451a
6
+ metadata.gz: 465c3dc7415da3ee83118227916a0d21a653fd8c74b2876a73e2510e545e7b210d0a96425d3f014ad997516f9314fea9de819b81deb373ec949162a3b7d6ca15
7
+ data.tar.gz: 231afe294759e0cc1fe0b0a884a99044808021e0d6d1f7201a8406f7a5b0b0128c6821f25b6d743d9c2475e9397c94dce10fc12ec831fbd123c7875495e067a1
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,18 @@ 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.0.0 (2024-12-07)
17
+
18
+ ### Changed
19
+
20
+ - Use atomic execution (MULTI/EXEC) where possible.
21
+
22
+ ## Falqon v0.1.0 (2024-11-16)
23
+
24
+ Initial release
25
+
26
+ ## Falqon v0.0.1 (2023-06-22)
27
+
28
+ [unreleased]: https://github.com/floriandejonckheere/falqon/compare/v1.0.0...HEAD
29
+ [1.0.0]: https://github.com/floriandejonckheere/falqon-pro/releases/tag/v1.0.0
30
+ [0.1.0]: https://github.com/floriandejonckheere/falqon-pro/releases/tag/v0.1.0
data/Gemfile CHANGED
@@ -14,7 +14,7 @@ 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
@@ -28,21 +28,21 @@ group :development, :test do
28
28
  gem "ffaker", "2.23.0", require: false
29
29
 
30
30
  # Mock Redis server
31
- gem "mock_redis", "0.45.0", require: false
31
+ gem "mock_redis", "0.48.1", 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
37
+ gem "rubocop", "1.69.0", require: false
38
38
  gem "rubocop-factory_bot", "2.26.1", require: false
39
- gem "rubocop-performance", "1.22.1", require: false
39
+ gem "rubocop-performance", "1.23.0", require: false
40
40
  gem "rubocop-rake", "0.6.0", require: false
41
41
  gem "rubocop-rspec", "3.2.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.11672", require: false
45
+ gem "tapioca", "0.16.5", 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:
@@ -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
 
@@ -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,8 +3,8 @@
3
3
  module Falqon
4
4
  # @!visibility private
5
5
  module Version
6
- MAJOR = 0
7
- MINOR = 1
6
+ MAJOR = 1
7
+ MINOR = 0
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
 
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.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: 2024-11-16 00:00:00.000000000 Z
11
+ date: 2024-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool
@@ -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
@@ -145,8 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
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: []