messaging 3.6.2 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +36 -34
- data/.env +1 -0
- data/Gemfile.lock +14 -30
- data/docker-compose.yml +62 -0
- data/lib/messaging/adapters/kafka/producer.rb +2 -2
- data/lib/messaging/adapters/postgres/categories/row.rb +30 -0
- data/lib/messaging/adapters/postgres/categories.rb +28 -13
- data/lib/messaging/adapters/postgres/category.rb +7 -21
- data/lib/messaging/adapters/postgres/category_with_partitions.rb +89 -0
- data/lib/messaging/adapters/postgres/store.rb +9 -0
- data/lib/messaging/adapters/test/category.rb +0 -4
- data/lib/messaging/message.rb +4 -0
- data/lib/messaging/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33403486d5e5dad21b6ed8b8d5c8e99d090ce19d79f5278e0aa5ee43dd43c8d5
|
4
|
+
data.tar.gz: d174552154912fe26401443c8b5e74b202c0faeb054f8ed6affad299843da91d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4477a3ec21fd27ca4735741ec690c8a9f9308c14b18b4c2236a04ba3991dec1fe16359896d1058bb5cf36fda9b2d119cdb8f79870237d1a4d4bed05be6561ac7
|
7
|
+
data.tar.gz: b8ec79f61ac86766d586f166053f829e7329f06e57366cfc88586ffd4a9d28d5047958f9fcf35f1c8ba50f489d48404b623d572197e10b7cdc8f654def0cb5f6
|
data/.circleci/config.yml
CHANGED
@@ -2,51 +2,53 @@
|
|
2
2
|
#
|
3
3
|
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
4
|
#
|
5
|
-
version: 2
|
6
|
-
|
7
|
-
|
8
|
-
docker:
|
9
|
-
- image: circleci/ruby:2.4.1-node-browsers
|
10
|
-
environment:
|
11
|
-
- CC_TEST_REPORTER_ID: 94ada9b95ee3f232a6e984809d37917cfee90ac47805429e8c49742b2e8d2276
|
12
|
-
- RAILS_ENV: test
|
13
|
-
- image: circleci/postgres:12.5-ram
|
14
|
-
environment:
|
15
|
-
- POSTGRES_HOST_AUTH_METHOD: trust
|
16
|
-
- POSTGRES_PASSWORD: password
|
5
|
+
version: 2.1
|
6
|
+
orbs:
|
7
|
+
slack: circleci/slack@4.8.2
|
17
8
|
|
18
|
-
|
9
|
+
shared: &shared
|
10
|
+
docker:
|
11
|
+
# https://github.com/bukowskis/fineart/wiki/Updating-the-development-docker-image-for-Circle-CI
|
12
|
+
- image: ghcr.io/bukowskis/base-image/development:ruby-2.6.6-v5
|
13
|
+
auth:
|
14
|
+
username: $GHCR_USER
|
15
|
+
password: $GHCR_PASSWORD
|
16
|
+
- image: cimg/postgres:12.11
|
17
|
+
environment:
|
18
|
+
- POSTGRES_HOST_AUTH_METHOD: trust
|
19
|
+
resource_class: large
|
20
|
+
environment:
|
21
|
+
- CC_TEST_REPORTER_ID: 94ada9b95ee3f232a6e984809d37917cfee90ac47805429e8c49742b2e8d2276
|
22
|
+
- DISABLE_SPRING: 1
|
23
|
+
- RACK_ENV: test
|
19
24
|
|
25
|
+
commands:
|
26
|
+
bundle_install:
|
20
27
|
steps:
|
21
|
-
- run:
|
22
|
-
name: Install aptitude because it has much more helpful error messages when ending up in dependency hell
|
23
|
-
command: sudo apt-get install --assume-yes aptitude
|
24
|
-
|
25
|
-
- run:
|
26
|
-
name: Install Postgres Client
|
27
|
-
command: sudo aptitude -y install postgresql-client
|
28
|
-
|
29
|
-
- checkout
|
30
|
-
|
31
|
-
- run:
|
32
|
-
name: Setup Code Climate test-reporter
|
33
|
-
command: |
|
34
|
-
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
35
|
-
chmod +x ./cc-test-reporter
|
36
|
-
|
37
28
|
- restore_cache:
|
38
29
|
name: Restore Bundler Cache
|
39
|
-
key:
|
30
|
+
key: bukowskis-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
|
40
31
|
|
41
32
|
- run:
|
42
|
-
name:
|
43
|
-
command: bundle install --jobs=4 --retry=3
|
33
|
+
name: Bundle Install
|
34
|
+
command: bundle install --path=vendor/bundle --jobs=4 --retry=3
|
44
35
|
|
45
36
|
- save_cache:
|
46
|
-
key:
|
37
|
+
key: bukowskis-bundle-{{ .Environment.CACHE_VERSION }}-{{ checksum "Gemfile.lock" }}
|
47
38
|
paths:
|
48
39
|
- vendor/bundle
|
49
40
|
|
41
|
+
jobs:
|
42
|
+
specs:
|
43
|
+
<<: *shared
|
44
|
+
steps:
|
45
|
+
- checkout
|
46
|
+
- bundle_install
|
47
|
+
- run:
|
48
|
+
name: Setup Code Climate test-reporter
|
49
|
+
command: |
|
50
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
51
|
+
chmod +x ./cc-test-reporter
|
50
52
|
- run:
|
51
53
|
name: Database Setup
|
52
54
|
command: |
|
@@ -65,4 +67,4 @@ workflows:
|
|
65
67
|
version: 2
|
66
68
|
messaging_specs:
|
67
69
|
jobs:
|
68
|
-
-
|
70
|
+
- specs
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
messaging (3.
|
4
|
+
messaging (3.7.1)
|
5
5
|
activerecord
|
6
6
|
activesupport
|
7
7
|
after_transaction
|
@@ -45,8 +45,8 @@ GEM
|
|
45
45
|
tzinfo (~> 1.1)
|
46
46
|
addressable (2.7.0)
|
47
47
|
public_suffix (>= 2.0.2, < 5.0)
|
48
|
-
after_transaction (0.0.
|
49
|
-
activerecord
|
48
|
+
after_transaction (0.0.5)
|
49
|
+
activerecord
|
50
50
|
arel (9.0.0)
|
51
51
|
axiom-types (0.1.1)
|
52
52
|
descendants_tracker (~> 0.0.4)
|
@@ -73,24 +73,23 @@ GEM
|
|
73
73
|
descendants_tracker (0.0.4)
|
74
74
|
thread_safe (~> 0.3, >= 0.3.1)
|
75
75
|
diff-lcs (1.3)
|
76
|
-
digest-crc (0.
|
76
|
+
digest-crc (0.6.0)
|
77
77
|
dnsruby (1.61.3)
|
78
78
|
addressable (~> 2.5)
|
79
79
|
docile (1.3.2)
|
80
|
-
dry-configurable (0.
|
80
|
+
dry-configurable (0.13.0)
|
81
81
|
concurrent-ruby (~> 1.0)
|
82
|
-
dry-core (~> 0.
|
83
|
-
dry-container (0.
|
82
|
+
dry-core (~> 0.6)
|
83
|
+
dry-container (0.9.0)
|
84
84
|
concurrent-ruby (~> 1.0)
|
85
|
-
dry-configurable (~> 0.
|
86
|
-
dry-core (0.
|
85
|
+
dry-configurable (~> 0.13, >= 0.13.0)
|
86
|
+
dry-core (0.7.1)
|
87
87
|
concurrent-ruby (~> 1.0)
|
88
|
-
dry-equalizer (0.
|
89
|
-
dry-initializer (3.0.
|
88
|
+
dry-equalizer (0.3.0)
|
89
|
+
dry-initializer (3.0.4)
|
90
90
|
em-websocket (0.5.1)
|
91
91
|
eventmachine (>= 0.12.9)
|
92
92
|
http_parser.rb (~> 0.6.0)
|
93
|
-
equalizer (0.0.11)
|
94
93
|
erubi (1.9.0)
|
95
94
|
ethon (0.12.0)
|
96
95
|
ffi (>= 1.3.0)
|
@@ -101,7 +100,6 @@ GEM
|
|
101
100
|
ffi (1.11.3)
|
102
101
|
forwardable-extended (2.6.0)
|
103
102
|
gemoji (3.0.1)
|
104
|
-
geocoder (1.2.13)
|
105
103
|
github-pages (203)
|
106
104
|
github-pages-health-check (= 1.16.1)
|
107
105
|
jekyll (= 3.8.5)
|
@@ -151,7 +149,6 @@ GEM
|
|
151
149
|
octokit (~> 4.0)
|
152
150
|
public_suffix (~> 3.0)
|
153
151
|
typhoeus (~> 1.3)
|
154
|
-
hashie (4.1.0)
|
155
152
|
html-pipeline (2.12.2)
|
156
153
|
activesupport (>= 2)
|
157
154
|
nokogiri (>= 1.4)
|
@@ -272,21 +269,11 @@ GEM
|
|
272
269
|
listen (3.2.1)
|
273
270
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
274
271
|
rb-inotify (~> 0.9, >= 0.9.10)
|
275
|
-
locality (1.1.0)
|
276
|
-
activesupport
|
277
|
-
geocoder (= 1.2.13)
|
278
|
-
hashie
|
279
|
-
i18n
|
280
|
-
maxminddb (= 0.1.8)
|
281
|
-
operation
|
282
|
-
trouble
|
283
272
|
loofah (2.4.0)
|
284
273
|
crass (~> 1.0.2)
|
285
274
|
nokogiri (>= 1.5.9)
|
286
|
-
maxminddb (0.1.8)
|
287
275
|
mercenary (0.3.6)
|
288
|
-
meter (1.
|
289
|
-
locality (~> 1.1.0)
|
276
|
+
meter (1.4.0)
|
290
277
|
useragent (~> 0.16.3)
|
291
278
|
method_object (1.0.0)
|
292
279
|
dry-initializer
|
@@ -303,7 +290,6 @@ GEM
|
|
303
290
|
mini_portile2 (~> 2.4.0)
|
304
291
|
octokit (4.14.0)
|
305
292
|
sawyer (~> 0.8.0, >= 0.5.3)
|
306
|
-
operation (1.4.1)
|
307
293
|
pathutil (0.16.2)
|
308
294
|
forwardable-extended (~> 2.6)
|
309
295
|
pg (1.1.4)
|
@@ -358,7 +344,7 @@ GEM
|
|
358
344
|
rspec-support (3.9.0)
|
359
345
|
ruby-enum (0.7.2)
|
360
346
|
i18n
|
361
|
-
ruby-kafka (1.
|
347
|
+
ruby-kafka (1.5.0)
|
362
348
|
digest-crc
|
363
349
|
rubyzip (1.3.0)
|
364
350
|
safe_yaml (1.0.5)
|
@@ -384,18 +370,16 @@ GEM
|
|
384
370
|
unicode-display_width (~> 1.1, >= 1.1.1)
|
385
371
|
thor (0.20.3)
|
386
372
|
thread_safe (0.3.6)
|
387
|
-
trouble (0.0.13)
|
388
373
|
typhoeus (1.3.1)
|
389
374
|
ethon (>= 0.9.0)
|
390
375
|
tzinfo (1.2.5)
|
391
376
|
thread_safe (~> 0.1)
|
392
377
|
unicode-display_width (1.6.0)
|
393
378
|
useragent (0.16.10)
|
394
|
-
virtus (
|
379
|
+
virtus (2.0.0)
|
395
380
|
axiom-types (~> 0.1)
|
396
381
|
coercible (~> 1.0)
|
397
382
|
descendants_tracker (~> 0.0, >= 0.0.3)
|
398
|
-
equalizer (~> 0.0, >= 0.0.9)
|
399
383
|
|
400
384
|
PLATFORMS
|
401
385
|
ruby
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
version: '3.4'
|
2
|
+
|
3
|
+
x-shared: &shared
|
4
|
+
tmpfs:
|
5
|
+
- /tmp
|
6
|
+
environment:
|
7
|
+
- RAILS_ENV=${RAILS_ENV:-development}
|
8
|
+
- BOOTSNAP_CACHE_DIR=/rails_cache/bootsnap
|
9
|
+
volumes:
|
10
|
+
- .:/app
|
11
|
+
- bundle:/usr/local/bundle
|
12
|
+
networks:
|
13
|
+
- ${NETWORK_NAME:-default}
|
14
|
+
|
15
|
+
services:
|
16
|
+
runner:
|
17
|
+
<<: *shared
|
18
|
+
image: ghcr.io/bukowskis/base-image/development:ruby-2.6.6-v5
|
19
|
+
stdin_open: true
|
20
|
+
tty: true
|
21
|
+
command: /bin/sh
|
22
|
+
|
23
|
+
postgres:
|
24
|
+
image: postgres:${PG_VERSION}
|
25
|
+
volumes:
|
26
|
+
- pg_data:/var/lib/postgresql/data
|
27
|
+
ports:
|
28
|
+
- 5432:5432
|
29
|
+
environment:
|
30
|
+
- POSTGRES_HOST_AUTH_METHOD=trust
|
31
|
+
|
32
|
+
zookeeper:
|
33
|
+
image: zookeeper
|
34
|
+
ports:
|
35
|
+
- "2181:2181"
|
36
|
+
|
37
|
+
kafka:
|
38
|
+
image: niks123123/kafka:2.7.0
|
39
|
+
ports:
|
40
|
+
- "9092:9092"
|
41
|
+
depends_on:
|
42
|
+
- zookeeper
|
43
|
+
environment:
|
44
|
+
KAFKA_ADVERTISED_HOST_NAME: kafka
|
45
|
+
KAFKA_ADVERTISED_PORT: 9092
|
46
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
47
|
+
KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true'
|
48
|
+
volumes:
|
49
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
50
|
+
|
51
|
+
volumes:
|
52
|
+
bundle:
|
53
|
+
name: bundle
|
54
|
+
pg_data:
|
55
|
+
name: pg_data_${PG_VERSION}
|
56
|
+
|
57
|
+
networks:
|
58
|
+
default:
|
59
|
+
name: messaging_default
|
60
|
+
external:
|
61
|
+
name: ${EXTERNAL_NETWORK}
|
62
|
+
external: true
|
@@ -20,8 +20,8 @@ module Messaging
|
|
20
20
|
def call(message)
|
21
21
|
reconnect if forked?
|
22
22
|
producer.produce(message.to_json, key: message.message_key, topic: message.topic)
|
23
|
-
rescue ::Kafka::BufferOverflow =>
|
24
|
-
|
23
|
+
rescue ::Kafka::BufferOverflow => e
|
24
|
+
ExceptionHandler.call(e, message: message.to_json)
|
25
25
|
end
|
26
26
|
|
27
27
|
def shutdown
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Adapters
|
3
|
+
class Postgres
|
4
|
+
class Categories
|
5
|
+
class Row
|
6
|
+
extend Dry::Initializer
|
7
|
+
|
8
|
+
param :table_name
|
9
|
+
param :type
|
10
|
+
param :expression
|
11
|
+
|
12
|
+
def category_class
|
13
|
+
return CategoryWithPartitions if type == 'p'
|
14
|
+
|
15
|
+
Category
|
16
|
+
end
|
17
|
+
|
18
|
+
def category_name
|
19
|
+
regexp = /FOR VALUES IN \(\'(.*)\'\)/
|
20
|
+
expression.match(regexp)[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_category
|
24
|
+
category_class.new(category_name, table_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -5,9 +5,7 @@ module Messaging
|
|
5
5
|
include Enumerable
|
6
6
|
|
7
7
|
def each
|
8
|
-
all_categories.each
|
9
|
-
yield Category.new(name)
|
10
|
-
end
|
8
|
+
all_categories.each { |c| yield c }
|
11
9
|
end
|
12
10
|
|
13
11
|
# Get a category by name
|
@@ -16,10 +14,7 @@ module Messaging
|
|
16
14
|
# @return [nil] if no category exists with the given name
|
17
15
|
# @return [Category]
|
18
16
|
def [](name)
|
19
|
-
|
20
|
-
return unless category
|
21
|
-
|
22
|
-
Category.new(category)
|
17
|
+
all_categories.find { |c| c.name == name }
|
23
18
|
end
|
24
19
|
|
25
20
|
# Creates a table partition for the given category
|
@@ -27,20 +22,36 @@ module Messaging
|
|
27
22
|
# @param name [String] the name of the category
|
28
23
|
# @return [Category]
|
29
24
|
def create(name)
|
30
|
-
table_name =
|
25
|
+
table_name = Category.table_name_for(name)
|
31
26
|
sql = <<~SQL
|
32
27
|
CREATE TABLE messaging.#{table_name}
|
33
28
|
PARTITION OF messaging.messages FOR VALUES IN ('#{name}');
|
34
29
|
SQL
|
35
30
|
connection.execute sql
|
36
|
-
Category.new(name)
|
31
|
+
Category.new(name, table_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Creates a table partition for the given category
|
35
|
+
# that in turn is partitioned based on created_at
|
36
|
+
#
|
37
|
+
# @param name [String] the name of the category
|
38
|
+
# @return [CategoryWithPartitions]
|
39
|
+
def create_and_partition_by_day(name)
|
40
|
+
table_name = Category.table_name_for(name)
|
41
|
+
sql = <<~SQL
|
42
|
+
CREATE TABLE messaging.#{table_name}
|
43
|
+
PARTITION OF messaging.messages FOR VALUES IN ('#{name}')
|
44
|
+
PARTITION BY RANGE (created_at);
|
45
|
+
SQL
|
46
|
+
connection.execute sql
|
47
|
+
CategoryWithPartitions.new(name, table_name)
|
37
48
|
end
|
38
49
|
|
39
50
|
# Drops the table partition (including all messages) for the given category
|
40
51
|
#
|
41
52
|
# @param name [String] the name of the category
|
42
53
|
def drop(name)
|
43
|
-
table_name =
|
54
|
+
table_name = Category.table_name_for(name)
|
44
55
|
sql = <<~SQL
|
45
56
|
drop TABLE messaging.#{table_name}
|
46
57
|
SQL
|
@@ -55,15 +66,19 @@ module Messaging
|
|
55
66
|
|
56
67
|
def fetch_categories
|
57
68
|
sql = <<~SQL
|
58
|
-
SELECT child.relname AS category
|
69
|
+
SELECT child.relname AS category,
|
70
|
+
child.relkind AS category_type,
|
71
|
+
pg_get_expr(child.relpartbound, child.oid, true) AS expression
|
59
72
|
FROM pg_inherits
|
60
73
|
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
|
61
74
|
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
|
62
75
|
JOIN pg_namespace ON pg_namespace.oid = parent.relnamespace
|
63
|
-
WHERE pg_namespace.nspname = 'messaging'
|
76
|
+
WHERE pg_namespace.nspname = 'messaging'
|
77
|
+
AND parent.relname = 'messages'
|
78
|
+
AND child.relkind in ('r', 'p')
|
64
79
|
ORDER BY category
|
65
80
|
SQL
|
66
|
-
connection.
|
81
|
+
connection.select_rows(sql).map { |r| Row.new(*r).to_category }
|
67
82
|
end
|
68
83
|
|
69
84
|
def connection
|
@@ -2,16 +2,13 @@ module Messaging
|
|
2
2
|
module Adapters
|
3
3
|
class Postgres
|
4
4
|
class Category
|
5
|
-
|
6
|
-
attr_reader :name
|
5
|
+
extend Dry::Initializer
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(name)
|
14
|
-
@name = name
|
7
|
+
param :name
|
8
|
+
param :table_name, default: -> { self.class.table_name_for(name) }
|
9
|
+
|
10
|
+
def self.table_name_for(name)
|
11
|
+
name.parameterize(separator: '_')
|
15
12
|
end
|
16
13
|
|
17
14
|
# Access to all messages in the category sorted by created_at
|
@@ -20,19 +17,8 @@ module Messaging
|
|
20
17
|
SerializedMessage.where(stream_category: name).order(:created_at)
|
21
18
|
end
|
22
19
|
|
23
|
-
def messages_older_than(time)
|
24
|
-
messages.where('created_at < ?', time)
|
25
|
-
end
|
26
|
-
|
27
|
-
def delete_messages_older_than!(time)
|
28
|
-
SerializedMessage.transaction do
|
29
|
-
ActiveRecord::Base.connection.execute "SET LOCAL statement_timeout = '0'"
|
30
|
-
messages_older_than(time).delete_all
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
20
|
def inspect
|
35
|
-
"#<Category
|
21
|
+
"#<Category: #{name}>"
|
36
22
|
end
|
37
23
|
end
|
38
24
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Messaging
|
2
|
+
module Adapters
|
3
|
+
class Postgres
|
4
|
+
class CategoryWithPartitions < Category
|
5
|
+
def add_partition(date:)
|
6
|
+
from, to = partition_range_for(date: date)
|
7
|
+
partition_name = partition_name_for(date: from)
|
8
|
+
|
9
|
+
return if partition_exists?(partition_name)
|
10
|
+
|
11
|
+
sql = <<~SQL
|
12
|
+
CREATE TABLE IF NOT EXISTS messaging.#{partition_name}
|
13
|
+
PARTITION OF messaging.#{table_name} FOR VALUES FROM ('#{from}') TO ('#{to}')
|
14
|
+
SQL
|
15
|
+
|
16
|
+
SerializedMessage.transaction do
|
17
|
+
AdvisoryTransactionLock.call key: partition_name
|
18
|
+
SerializedMessage.connection.execute sql
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates multiple partitions
|
23
|
+
#
|
24
|
+
# @param start_date [Date] from which date to create partitions
|
25
|
+
# @param days [Integer] how many days worth of partitions to create
|
26
|
+
def add_partitions(start_date:, days: 1)
|
27
|
+
first = start_date.to_date
|
28
|
+
last = first + (days - 1)
|
29
|
+
|
30
|
+
(first..last).each do |date|
|
31
|
+
add_partition(date: date)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Removes a partition including the included messages
|
36
|
+
#
|
37
|
+
# @param partition_name [String] the name of the partition to drop
|
38
|
+
def drop_partition(partition_name)
|
39
|
+
return unless partition_name.match?(/^#{table_name}_\d{4}_\d{2}_\d{2}$/)
|
40
|
+
|
41
|
+
SerializedMessage.connection.execute "drop TABLE messaging.#{partition_name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Removes all partitions older than the given date
|
45
|
+
#
|
46
|
+
# @param date [Date] the cutoff date
|
47
|
+
def drop_partitions_older_than(date)
|
48
|
+
max_partition_name = partition_name_for(date: date)
|
49
|
+
partitions.select { |p| p < max_partition_name }.each do |p|
|
50
|
+
drop_partition(p)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def partition_name_for(date:)
|
55
|
+
"#{name}_%d_%02d_%02d" % [date.year, date.month, date.day]
|
56
|
+
end
|
57
|
+
|
58
|
+
def partition_range_for(date:)
|
59
|
+
from = date.to_time.beginning_of_day
|
60
|
+
to = from + 1.day
|
61
|
+
[from, to]
|
62
|
+
end
|
63
|
+
|
64
|
+
def partition_exists?(partition_name)
|
65
|
+
partitions.include? partition_name
|
66
|
+
end
|
67
|
+
|
68
|
+
def partitions
|
69
|
+
sql = <<~SQL
|
70
|
+
SELECT child.relname AS name
|
71
|
+
FROM pg_inherits
|
72
|
+
JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
|
73
|
+
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
|
74
|
+
JOIN pg_namespace ON pg_namespace.oid = parent.relnamespace
|
75
|
+
WHERE pg_namespace.nspname = 'messaging'
|
76
|
+
AND parent.relname = '#{table_name}'
|
77
|
+
AND child.relkind = 'r'
|
78
|
+
ORDER BY name
|
79
|
+
SQL
|
80
|
+
SerializedMessage.connection.select_values(sql)
|
81
|
+
end
|
82
|
+
|
83
|
+
def inspect
|
84
|
+
"#<CategoryWithPartitions: #{name}>"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require_relative 'category'
|
2
|
+
require_relative 'category_with_partitions'
|
2
3
|
require_relative 'categories'
|
4
|
+
require_relative 'categories/row'
|
3
5
|
require_relative 'stream'
|
4
6
|
require_relative 'streams'
|
5
7
|
|
@@ -83,6 +85,13 @@ module Messaging
|
|
83
85
|
return message unless message.stream_name
|
84
86
|
|
85
87
|
SerializedMessage.create!(message: message).to_message
|
88
|
+
rescue ActiveRecord::StatementInvalid => e
|
89
|
+
category = message.category
|
90
|
+
raise e unless e.message.include?('no partition of relation')
|
91
|
+
raise e unless category || category.is_a?(CategoryWithPartitions)
|
92
|
+
|
93
|
+
category.add_partition(date: Date.today)
|
94
|
+
retry
|
86
95
|
end
|
87
96
|
end
|
88
97
|
end
|
data/lib/messaging/message.rb
CHANGED
data/lib/messaging/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: messaging
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bukowskis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -271,6 +271,7 @@ extensions: []
|
|
271
271
|
extra_rdoc_files: []
|
272
272
|
files:
|
273
273
|
- ".circleci/config.yml"
|
274
|
+
- ".env"
|
274
275
|
- ".gitignore"
|
275
276
|
- ".rspec"
|
276
277
|
- Gemfile
|
@@ -282,6 +283,7 @@ files:
|
|
282
283
|
- _layouts/single.html
|
283
284
|
- bin/console
|
284
285
|
- bin/setup
|
286
|
+
- docker-compose.yml
|
285
287
|
- docs/adapters.md
|
286
288
|
- docs/consuming.md
|
287
289
|
- docs/installation.md
|
@@ -297,7 +299,9 @@ files:
|
|
297
299
|
- lib/messaging/adapters/postgres.rb
|
298
300
|
- lib/messaging/adapters/postgres/advisory_transaction_lock.rb
|
299
301
|
- lib/messaging/adapters/postgres/categories.rb
|
302
|
+
- lib/messaging/adapters/postgres/categories/row.rb
|
300
303
|
- lib/messaging/adapters/postgres/category.rb
|
304
|
+
- lib/messaging/adapters/postgres/category_with_partitions.rb
|
301
305
|
- lib/messaging/adapters/postgres/serialized_message.rb
|
302
306
|
- lib/messaging/adapters/postgres/store.rb
|
303
307
|
- lib/messaging/adapters/postgres/stream.rb
|