sbmt-outbox 6.11.0 → 6.13.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/README.md +4 -2
- data/app/jobs/sbmt/outbox/base_delete_stale_items_job.rb +74 -24
- data/app/models/sbmt/outbox/base_item_config.rb +7 -0
- data/config/initializers/yabeda.rb +10 -0
- data/lib/sbmt/outbox/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47ab689de26112df54d99c701fad3c6f492096173de831fc134318afa91c6662
|
|
4
|
+
data.tar.gz: b11e20111becd1d58cfca72a98d62adeb1b7573c0c093081b086331d90cc7b04
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6df07282a29bf4468399747b2443965c35bcbc8590bcb5b6613fdad8c255cad9296dfdf9662399617f15ce39cd589e6f022a4da3c8611ee9d712714a10d36fcf
|
|
7
|
+
data.tar.gz: 0f14e1ed6c00ed9fd2c4fd4e9ff225330b507f0a9fbef4c39a32e86eeb0a7bebbf194a2b4040f5b4e2813b8438f27bb78a9a024b16784397ff0fe712143b505f
|
data/README.md
CHANGED
|
@@ -267,7 +267,8 @@ default: &default
|
|
|
267
267
|
outbox_items: # outbox items section
|
|
268
268
|
my_outbox_item: # underscored model class name
|
|
269
269
|
owner: my_outbox_item_team # optional, used in Yabeda metrics
|
|
270
|
-
retention: P1W # retention period, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
270
|
+
retention: P1W # for statuses: failed and discarded, retention period, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
271
|
+
retention_delivered_items: PT6H # for statuses: delivered, retention period for delivered items, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
271
272
|
max_retries: 3 # default 0, the number of retries before the item will be marked as failed
|
|
272
273
|
strict_order: false # optional, default
|
|
273
274
|
transports: # transports section
|
|
@@ -342,7 +343,8 @@ end
|
|
|
342
343
|
inbox_items: # inbox items section
|
|
343
344
|
my_inbox_item: # underscored model class name
|
|
344
345
|
owner: my_inbox_item_team # optional, used in Yabeda metrics
|
|
345
|
-
retention: P1W # retention period, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
346
|
+
retention: P1W # for statuses: failed and discarded, retention period, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
347
|
+
retention_delivered_items: PT6H # for statuses: delivered, retention period for delivered items, https://en.wikipedia.org/wiki/ISO_8601#Durations
|
|
346
348
|
max_retries: 3 # default 0, the number of retries before the item will be marked as failed
|
|
347
349
|
transports: # transports section
|
|
348
350
|
import_order: # underscored transport class name
|
|
@@ -13,7 +13,8 @@ module Sbmt
|
|
|
13
13
|
class << self
|
|
14
14
|
def enqueue
|
|
15
15
|
item_classes.each do |item_class|
|
|
16
|
-
|
|
16
|
+
delay = rand(15).seconds
|
|
17
|
+
set(wait: delay).perform_later(item_class.to_s)
|
|
17
18
|
end
|
|
18
19
|
end
|
|
19
20
|
|
|
@@ -41,12 +42,13 @@ module Sbmt
|
|
|
41
42
|
|
|
42
43
|
lock_manager.lock("#{self.class.name}:#{item_class_name}:lock", LOCK_TTL) do |locked|
|
|
43
44
|
if locked
|
|
44
|
-
|
|
45
|
+
duration_failed = item_class.config.retention
|
|
46
|
+
duration_delivered = item_class.config.retention_delivered_items
|
|
45
47
|
|
|
46
|
-
validate_retention!(
|
|
48
|
+
validate_retention!(duration_failed)
|
|
47
49
|
|
|
48
50
|
logger.with_tags(box_type: box_type, box_name: box_name) do
|
|
49
|
-
delete_stale_items(Time.current -
|
|
51
|
+
delete_stale_items(Time.current - duration_failed, Time.current - duration_delivered)
|
|
50
52
|
end
|
|
51
53
|
else
|
|
52
54
|
logger.log_info("Failed to acquire lock #{self.class.name}:#{item_class_name}")
|
|
@@ -58,25 +60,25 @@ module Sbmt
|
|
|
58
60
|
|
|
59
61
|
private
|
|
60
62
|
|
|
61
|
-
def validate_retention!(
|
|
62
|
-
return if
|
|
63
|
+
def validate_retention!(duration_failed)
|
|
64
|
+
return if duration_failed >= MIN_RETENTION_PERIOD
|
|
63
65
|
|
|
64
66
|
raise "Retention period for #{box_name} must be longer than #{MIN_RETENTION_PERIOD.inspect}"
|
|
65
67
|
end
|
|
66
68
|
|
|
67
|
-
def delete_stale_items(
|
|
68
|
-
logger.log_info("Start deleting #{box_type} items for #{box_name} older than #{
|
|
69
|
+
def delete_stale_items(waterline_failed, waterline_delivered)
|
|
70
|
+
logger.log_info("Start deleting #{box_type} items for #{box_name} older than: failed and discarded items #{waterline_failed} and delivered items #{waterline_delivered}")
|
|
69
71
|
|
|
70
72
|
case database_type
|
|
71
73
|
when :postgresql
|
|
72
|
-
postgres_delete_in_batches(
|
|
74
|
+
postgres_delete_in_batches(waterline_failed, waterline_delivered)
|
|
73
75
|
when :mysql
|
|
74
|
-
mysql_delete_in_batches(
|
|
76
|
+
mysql_delete_in_batches(waterline_failed, waterline_delivered)
|
|
75
77
|
else
|
|
76
78
|
raise "Unsupported database type"
|
|
77
79
|
end
|
|
78
80
|
|
|
79
|
-
logger.log_info("Successfully deleted #{box_type} items for #{box_name} older than #{
|
|
81
|
+
logger.log_info("Successfully deleted #{box_type} items for #{box_name} older than: failed and discarded items #{waterline_failed} and delivered items #{waterline_delivered}")
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
# Deletes stale items from PostgreSQL database in batches
|
|
@@ -90,12 +92,22 @@ module Sbmt
|
|
|
90
92
|
# WHERE "items"."id" IN (
|
|
91
93
|
# SELECT "items"."id"
|
|
92
94
|
# FROM "items"
|
|
93
|
-
# WHERE
|
|
95
|
+
# WHERE (
|
|
96
|
+
# "items"."status" = 1 AND "items"."created_at" < '2023-05-01 00:00:00'
|
|
97
|
+
# )
|
|
94
98
|
# LIMIT 1000
|
|
95
99
|
# )
|
|
96
|
-
def postgres_delete_in_batches(
|
|
100
|
+
def postgres_delete_in_batches(waterline_failed, waterline_delivered)
|
|
97
101
|
table = item_class.arel_table
|
|
98
|
-
|
|
102
|
+
|
|
103
|
+
status_delivered = item_class.statuses[:delivered]
|
|
104
|
+
status_failed_discarded = item_class.statuses.values_at(:failed, :discarded)
|
|
105
|
+
|
|
106
|
+
delete_items_in_batches(table, table[:status].eq(status_delivered).and(table[:created_at].lt(waterline_delivered)))
|
|
107
|
+
delete_items_in_batches(table, table[:status].in(status_failed_discarded).and(table[:created_at].lt(waterline_failed)))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def delete_items_in_batches(table, condition)
|
|
99
111
|
subquery = table
|
|
100
112
|
.project(table[:id])
|
|
101
113
|
.where(condition)
|
|
@@ -104,12 +116,17 @@ module Sbmt
|
|
|
104
116
|
delete_statement = Arel::Nodes::DeleteStatement.new
|
|
105
117
|
delete_statement.relation = table
|
|
106
118
|
delete_statement.wheres = [table[:id].in(subquery)]
|
|
119
|
+
deleted_count = nil
|
|
107
120
|
|
|
108
121
|
loop do
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
122
|
+
track_deleted_latency do
|
|
123
|
+
deleted_count = item_class
|
|
124
|
+
.connection
|
|
125
|
+
.execute(delete_statement.to_sql)
|
|
126
|
+
.cmd_tuples
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
track_deleted_counter(deleted_count)
|
|
113
130
|
|
|
114
131
|
logger.log_info("Deleted #{deleted_count} #{box_type} items for #{box_name} items")
|
|
115
132
|
break if deleted_count == 0
|
|
@@ -129,14 +146,31 @@ module Sbmt
|
|
|
129
146
|
#
|
|
130
147
|
# Example SQL generated for deletion:
|
|
131
148
|
# DELETE FROM `items`
|
|
132
|
-
# WHERE
|
|
149
|
+
# WHERE (
|
|
150
|
+
# `items`.`status` = 1 AND `items`.`created_at` < '2023-05-01 00:00:00'
|
|
151
|
+
# )
|
|
133
152
|
# LIMIT 1000
|
|
134
|
-
def mysql_delete_in_batches(
|
|
153
|
+
def mysql_delete_in_batches(waterline_failed, waterline_delivered)
|
|
154
|
+
status_delivered = item_class.statuses[:delivered]
|
|
155
|
+
status_failed_discarded = [item_class.statuses.values_at(:failed, :discarded)]
|
|
156
|
+
|
|
157
|
+
delete_items_in_batches_mysql(
|
|
158
|
+
item_class.where(status: status_delivered, created_at: ...waterline_delivered)
|
|
159
|
+
)
|
|
160
|
+
delete_items_in_batches_mysql(
|
|
161
|
+
item_class.where(status: status_failed_discarded).where(created_at: ...waterline_failed)
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def delete_items_in_batches_mysql(query)
|
|
166
|
+
deleted_count = nil
|
|
167
|
+
|
|
135
168
|
loop do
|
|
136
|
-
|
|
137
|
-
.
|
|
138
|
-
|
|
139
|
-
|
|
169
|
+
track_deleted_latency do
|
|
170
|
+
deleted_count = query.limit(BATCH_SIZE).delete_all
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
track_deleted_counter(deleted_count)
|
|
140
174
|
|
|
141
175
|
logger.log_info("Deleted #{deleted_count} #{box_type} items for #{box_name} items")
|
|
142
176
|
break if deleted_count == 0
|
|
@@ -156,6 +190,22 @@ module Sbmt
|
|
|
156
190
|
:unknown
|
|
157
191
|
end
|
|
158
192
|
end
|
|
193
|
+
|
|
194
|
+
def track_deleted_counter(deleted_count)
|
|
195
|
+
::Yabeda
|
|
196
|
+
.outbox
|
|
197
|
+
.deleted_counter
|
|
198
|
+
.increment({box_type: box_type, box_name: box_name}, by: deleted_count)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def track_deleted_latency
|
|
202
|
+
::Yabeda
|
|
203
|
+
.outbox
|
|
204
|
+
.delete_latency
|
|
205
|
+
.measure({box_type: box_type, box_name: box_name}) do
|
|
206
|
+
yield
|
|
207
|
+
end
|
|
208
|
+
end
|
|
159
209
|
end
|
|
160
210
|
end
|
|
161
211
|
end
|
|
@@ -37,6 +37,13 @@ module Sbmt
|
|
|
37
37
|
@retention ||= ActiveSupport::Duration.parse(options[:retention] || "P1W")
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
def retention_delivered_items
|
|
41
|
+
@retention_delivered_items ||= begin
|
|
42
|
+
value = options[:retention_delivered_items] || retention
|
|
43
|
+
value.is_a?(String) ? ActiveSupport::Duration.parse(value) : value
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
40
47
|
def max_retries
|
|
41
48
|
@max_retries ||= (options[:max_retries] || 0).to_i
|
|
42
49
|
end
|
|
@@ -43,6 +43,16 @@ Yabeda.configure do
|
|
|
43
43
|
unit: :seconds,
|
|
44
44
|
buckets: [0.5, 1, 2.5, 5, 10, 15, 20, 30, 45, 60, 300].freeze,
|
|
45
45
|
comment: "A histogram outbox process latency"
|
|
46
|
+
|
|
47
|
+
histogram :delete_latency,
|
|
48
|
+
tags: %i[box_type box_name],
|
|
49
|
+
unit: :seconds,
|
|
50
|
+
buckets: [0.005, 0.01, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 20, 30].freeze,
|
|
51
|
+
comment: "A histogram for outbox/inbox deletion latency"
|
|
52
|
+
|
|
53
|
+
counter :deleted_counter,
|
|
54
|
+
tags: %i[box_type box_name],
|
|
55
|
+
comment: "A counter for the number of deleted outbox/inbox items"
|
|
46
56
|
end
|
|
47
57
|
|
|
48
58
|
group :box_worker do
|
data/lib/sbmt/outbox/version.rb
CHANGED
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.
|
|
4
|
+
version: 6.13.0
|
|
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:
|
|
11
|
+
date: 2025-01-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: connection_pool
|