sbmt-outbox 6.10.2 → 6.10.3

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: 5b9f32bdc55d20994a9ccd6a7c448b68b1732e9c0667ed06494b594635188dad
4
- data.tar.gz: da53b24ea40c840c5324ee3176f8341b4e0f96e19d6905dcd1e1df93f49913b0
3
+ metadata.gz: fabf75c06b0dea9c159918fe4496d3ffd47aa71caa1c364a6bfbef8c16a93494
4
+ data.tar.gz: d3c9b3a1bdfd55a0331b7e4fb971ac629c91b66cb952f4abb659e2b046a50187
5
5
  SHA512:
6
- metadata.gz: 721fcc1d9eb752ec086cb51407f6f387c33bde2d11c0ef57046154dc1ccf7a9d2eb34b61ac4a3668dcff0893ae4c394cea216605d2bd9780e417facb2ff2b215
7
- data.tar.gz: 2eac4d443109be1ba47d0d2acff62eb3151cc7f9425d7eb71478fec2b5f478fe4824b8270ed0d763fc1f2aa93390c5f6cfd17f43fe2a851f7eca851050c459fa
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sbmt
4
4
  module Outbox
5
- VERSION = "6.10.2"
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.2
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-10-01 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