sbmt-outbox 6.10.1 → 6.10.3

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: 563533826523f381bff35759aecedd3f1b5ed4e20067725e7f28d0a94808ab89
4
- data.tar.gz: 3a974ff0df4cf3a771888b521d33e9d5b5df367973b9a43fc6dfd4f6418caed0
3
+ metadata.gz: fabf75c06b0dea9c159918fe4496d3ffd47aa71caa1c364a6bfbef8c16a93494
4
+ data.tar.gz: d3c9b3a1bdfd55a0331b7e4fb971ac629c91b66cb952f4abb659e2b046a50187
5
5
  SHA512:
6
- metadata.gz: 4af541b2e8db7fa1fec41071caf150a1df4e973a1f93bfc2491288d0d4fe69a49d20cc9ebd96dcb378d0b6cc381baef68b8dbd5cfde8fdb062730125fdcac120
7
- data.tar.gz: 8274526f2a1c4fa433a20787ef14b07b83de4d11fa5d87f9ba30c7639bbb1396d4ae0fcec6d07493336d050ff757324e9bf88d14495e1ac803c1bf074a71734b
6
+ metadata.gz: ff0b3cce600d2b1b82750036da4819d21715d05956491b0b9d7f056bb62800fc1e49b72ae069b978196c06671cd7157f0b0e78cb133e80819d16e191da5d533d
7
+ data.tar.gz: 99754cf0cb25199388a3dd3457c5d8225ff3a1cc6b8a16da2c67c69efd999268597be2aa2a2fba13a24e484e262ea59f382af2699da048143432cd97a74a3516
@@ -7,8 +7,8 @@ module Sbmt
7
7
  class BaseDeleteStaleItemsJob < Outbox.active_job_base_class
8
8
  MIN_RETENTION_PERIOD = 1.day
9
9
  LOCK_TTL = 10_800_000
10
- BATCH_SIZE = 1000
11
- SLEEP_TIME = 1
10
+ BATCH_SIZE = 1_000
11
+ SLEEP_TIME = 0.5
12
12
 
13
13
  class << self
14
14
  def enqueue
@@ -25,7 +25,7 @@ module Sbmt
25
25
  delegate :config, :logger, to: "Sbmt::Outbox"
26
26
  delegate :box_type, :box_name, to: :item_class
27
27
 
28
- attr_accessor :item_class
28
+ attr_accessor :item_class, :lock_timer
29
29
 
30
30
  def perform(item_class_name)
31
31
  self.item_class = item_class_name.constantize
@@ -36,6 +36,7 @@ module Sbmt
36
36
  Redis.new(config.redis)
37
37
  end
38
38
 
39
+ self.lock_timer = Cutoff.new(LOCK_TTL / 1000)
39
40
  lock_manager = Redlock::Client.new([client], retry_count: 0)
40
41
 
41
42
  lock_manager.lock("#{self.class.name}:#{item_class_name}:lock", LOCK_TTL) do |locked|
@@ -51,6 +52,8 @@ module Sbmt
51
52
  logger.log_info("Failed to acquire lock #{self.class.name}:#{item_class_name}")
52
53
  end
53
54
  end
55
+ rescue Cutoff::CutoffExceededError
56
+ logger.log_info("Lock timeout while processing #{item_class_name}")
54
57
  end
55
58
 
56
59
  private
@@ -64,17 +67,94 @@ module Sbmt
64
67
  def delete_stale_items(waterline)
65
68
  logger.log_info("Start deleting #{box_type} items for #{box_name} older than #{waterline}")
66
69
 
70
+ case database_type
71
+ when :postgresql
72
+ postgres_delete_in_batches(waterline)
73
+ when :mysql
74
+ mysql_delete_in_batches(waterline)
75
+ else
76
+ raise "Unsupported database type"
77
+ end
78
+
79
+ logger.log_info("Successfully deleted #{box_type} items for #{box_name} older than #{waterline}")
80
+ end
81
+
82
+ # Deletes stale items from PostgreSQL database in batches
83
+ #
84
+ # This method efficiently deletes items older than the given waterline
85
+ # using a subquery approach to avoid locking large portions of the table.
86
+ #
87
+ #
88
+ # Example SQL generated for deletion:
89
+ # DELETE FROM "items"
90
+ # WHERE "items"."id" IN (
91
+ # SELECT "items"."id"
92
+ # FROM "items"
93
+ # WHERE "items"."created_at" < '2023-05-01 00:00:00'
94
+ # LIMIT 1000
95
+ # )
96
+ def postgres_delete_in_batches(waterline)
97
+ table = item_class.arel_table
98
+ condition = table[:created_at].lt(waterline)
99
+ subquery = table
100
+ .project(table[:id])
101
+ .where(condition)
102
+ .take(BATCH_SIZE)
103
+
104
+ delete_statement = Arel::Nodes::DeleteStatement.new
105
+ delete_statement.relation = table
106
+ delete_statement.wheres = [table[:id].in(subquery)]
107
+
67
108
  loop do
68
- ids = Outbox.database_switcher.use_slave do
69
- item_class.where("created_at < ?", waterline).limit(BATCH_SIZE).ids
70
- end
71
- break if ids.empty?
109
+ deleted_count = item_class
110
+ .connection
111
+ .execute(delete_statement.to_sql)
112
+ .cmd_tuples
113
+
114
+ logger.log_info("Deleted #{deleted_count} #{box_type} items for #{box_name} items")
115
+ break if deleted_count == 0
116
+ lock_timer.checkpoint!
117
+ sleep(SLEEP_TIME)
118
+ end
119
+ end
72
120
 
73
- item_class.where(id: ids).delete_all
74
- sleep SLEEP_TIME
121
+ # Deletes stale items from MySQL database in batches
122
+ #
123
+ # This method efficiently deletes items older than the given waterline
124
+ # using MySQL's built-in LIMIT clause for DELETE statements.
125
+ #
126
+ # The main difference from the PostgreSQL method is that MySQL allows
127
+ # direct use of LIMIT in DELETE statements, simplifying the query.
128
+ # This approach doesn't require a subquery, making it more straightforward.
129
+ #
130
+ # Example SQL generated for deletion:
131
+ # DELETE FROM `items`
132
+ # WHERE `items`.`created_at` < '2023-05-01 00:00:00'
133
+ # LIMIT 1000
134
+ def mysql_delete_in_batches(waterline)
135
+ loop do
136
+ deleted_count = item_class
137
+ .where("created_at < ?", waterline)
138
+ .limit(BATCH_SIZE)
139
+ .delete_all
140
+
141
+ logger.log_info("Deleted #{deleted_count} #{box_type} items for #{box_name} items")
142
+ break if deleted_count == 0
143
+ lock_timer.checkpoint!
144
+ sleep(SLEEP_TIME)
75
145
  end
146
+ end
76
147
 
77
- logger.log_info("Successfully deleted #{box_type} items for #{box_name} older than #{waterline}")
148
+ def database_type
149
+ adapter_name = item_class.connection.adapter_name.downcase
150
+ case adapter_name
151
+ when "postgresql"
152
+ :postgresql
153
+ when "mysql2"
154
+ :mysql
155
+ else
156
+ :unknown
157
+ end
78
158
  end
79
159
  end
80
160
  end
@@ -74,7 +74,7 @@ module Sbmt
74
74
  def partition_strategy
75
75
  return @partition_strategy if defined?(@partition_strategy)
76
76
 
77
- str_name = options.fetch(:partition_strategy, DEFAULT_PARTITION_STRATEGY)
77
+ str_name = options.fetch(:partition_strategy, DEFAULT_PARTITION_STRATEGY).to_s
78
78
  @partition_strategy = "Sbmt::Outbox::PartitionStrategies::#{str_name.camelize}Partitioning".constantize
79
79
  end
80
80
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sbmt
4
4
  module Outbox
5
- VERSION = "6.10.1"
5
+ VERSION = "6.10.3"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sbmt-outbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.10.1
4
+ version: 6.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sbermarket Ruby-Platform Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-25 00:00:00.000000000 Z
11
+ date: 2024-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool
@@ -348,56 +348,42 @@ dependencies:
348
348
  requirements:
349
349
  - - ">="
350
350
  - !ruby/object:Gem::Version
351
- version: '0'
351
+ version: '2.5'
352
352
  type: :development
353
353
  prerelease: false
354
354
  version_requirements: !ruby/object:Gem::Requirement
355
355
  requirements:
356
356
  - - ">="
357
357
  - !ruby/object:Gem::Version
358
- version: '0'
358
+ version: '2.5'
359
359
  - !ruby/object:Gem::Dependency
360
360
  name: rubocop-rspec
361
361
  requirement: !ruby/object:Gem::Requirement
362
362
  requirements:
363
363
  - - ">="
364
364
  - !ruby/object:Gem::Version
365
- version: '0'
365
+ version: '2.11'
366
366
  type: :development
367
367
  prerelease: false
368
368
  version_requirements: !ruby/object:Gem::Requirement
369
369
  requirements:
370
370
  - - ">="
371
371
  - !ruby/object:Gem::Version
372
- version: '0'
373
- - !ruby/object:Gem::Dependency
374
- name: rubocop-performance
375
- requirement: !ruby/object:Gem::Requirement
376
- requirements:
377
- - - ">="
378
- - !ruby/object:Gem::Version
379
- version: '0'
380
- type: :development
381
- prerelease: false
382
- version_requirements: !ruby/object:Gem::Requirement
383
- requirements:
384
- - - ">="
385
- - !ruby/object:Gem::Version
386
- version: '0'
372
+ version: '2.11'
387
373
  - !ruby/object:Gem::Dependency
388
374
  name: standard
389
375
  requirement: !ruby/object:Gem::Requirement
390
376
  requirements:
391
377
  - - ">="
392
378
  - !ruby/object:Gem::Version
393
- version: '1.7'
379
+ version: '1.12'
394
380
  type: :development
395
381
  prerelease: false
396
382
  version_requirements: !ruby/object:Gem::Requirement
397
383
  requirements:
398
384
  - - ">="
399
385
  - !ruby/object:Gem::Version
400
- version: '1.7'
386
+ version: '1.12'
401
387
  - !ruby/object:Gem::Dependency
402
388
  name: schked
403
389
  requirement: !ruby/object:Gem::Requirement
@@ -640,7 +626,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
640
626
  - !ruby/object:Gem::Version
641
627
  version: '0'
642
628
  requirements: []
643
- rubygems_version: 3.1.6
629
+ rubygems_version: 3.5.21
644
630
  signing_key:
645
631
  specification_version: 4
646
632
  summary: Outbox service