saseo 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/saseo_publisher +5 -1
- data/lib/generators/saseo/templates/add_saseo_trigger_function.rb +2 -7
- data/lib/saseo/config/defaults.rb +3 -1
- data/lib/saseo/config.rb +1 -1
- data/lib/saseo/extensions/active_record/adapter_mixin.rb +1 -39
- data/lib/saseo/persistence/consumer.rb +1 -1
- data/lib/saseo/persistence/persistor.rb +8 -3
- data/lib/saseo/publishing/publisher.rb +15 -32
- data/lib/saseo/version.rb +1 -1
- data/saseo.example.yml +8 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d3227155157a0d8e3df890b3e066aea67e73d68
|
4
|
+
data.tar.gz: 6673eb5e80dca1a684f97708e9f40bfced88b188
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f86a332905806cee8e96e3f00104a87fa48de5b1c391e7f9dcaeceaf9d17260e968da2ae1675f31d3fb59e0e5b14418937d55f80d5c1752875c4bd080503a2f
|
7
|
+
data.tar.gz: 68206c9fa409dbdb4430ea92dab8824b7f7d3b9929b89d257506b20ec8f3783bc9317c31fa4ef082b3e21d807dc11f98fa5f951fb5b1cf04c835c2b1391b1b9e
|
data/exe/saseo_publisher
CHANGED
@@ -4,7 +4,8 @@ class AddSaseoTriggerFunction < ActiveRecord::Migration
|
|
4
4
|
uuid_extension_sql = 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
|
5
5
|
|
6
6
|
audit_table_sql = <<SQL
|
7
|
-
CREATE schema saseo;
|
7
|
+
CREATE schema IF NOT EXISTS saseo;
|
8
|
+
DROP TABLE IF EXISTS saseo.saseo_source_versions;
|
8
9
|
|
9
10
|
CREATE TABLE saseo.saseo_source_versions (
|
10
11
|
id uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
|
@@ -41,34 +42,28 @@ DECLARE
|
|
41
42
|
v_old_data json;
|
42
43
|
v_new_data json;
|
43
44
|
v_whodunnit text;
|
44
|
-
v_channel text;
|
45
45
|
v_audit_uuid uuid;
|
46
46
|
BEGIN
|
47
47
|
v_whodunnit := saseo.whodunnit();
|
48
48
|
v_audit_uuid := uuid_generate_v4();
|
49
49
|
|
50
|
-
v_channel := upper('SASEO' || '_' || TG_TABLE_NAME::TEXT || '_' || TG_OP || '_AUDIT');
|
51
|
-
|
52
50
|
IF (TG_OP = 'UPDATE') THEN
|
53
51
|
v_old_data := row_to_json(OLD);
|
54
52
|
v_new_data := row_to_json(NEW);
|
55
53
|
|
56
54
|
INSERT INTO saseo.saseo_source_versions VALUES(v_audit_uuid, txid_current(), TG_TABLE_NAME, DEFAULT, TG_OP, v_whodunnit, v_old_data::JSONB, v_new_data::JSONB);
|
57
|
-
PERFORM pg_notify(v_channel, v_audit_uuid::TEXT);
|
58
55
|
|
59
56
|
RETURN NEW;
|
60
57
|
ELSIF (TG_OP = 'DELETE') THEN
|
61
58
|
v_old_data := row_to_json(OLD);
|
62
59
|
|
63
60
|
INSERT INTO saseo.saseo_source_versions VALUES(v_audit_uuid, txid_current(), TG_TABLE_NAME, DEFAULT, TG_OP, v_whodunnit, v_old_data::JSONB, NULL);
|
64
|
-
PERFORM pg_notify(v_channel, v_audit_uuid::TEXT);
|
65
61
|
|
66
62
|
RETURN OLD;
|
67
63
|
ELSIF (TG_OP = 'INSERT') THEN
|
68
64
|
v_new_data := row_to_json(NEW);
|
69
65
|
|
70
66
|
INSERT INTO saseo.saseo_source_versions VALUES(v_audit_uuid, txid_current(), TG_TABLE_NAME, DEFAULT, TG_OP, v_whodunnit, NULL, v_new_data::JSONB);
|
71
|
-
PERFORM pg_notify(v_channel, v_audit_uuid::TEXT);
|
72
67
|
|
73
68
|
RETURN NEW;
|
74
69
|
ELSE
|
@@ -2,7 +2,7 @@ module Saseo
|
|
2
2
|
class Config
|
3
3
|
module Defaults
|
4
4
|
|
5
|
-
|
5
|
+
PUBLISHER_BATCH_SIZE = 1000
|
6
6
|
SOURCE_DATABASE_URL = nil
|
7
7
|
SOURCE_DATABASE_CONFIG_PATH = 'config/database.yml'
|
8
8
|
DATABASE_URL = nil
|
@@ -27,6 +27,8 @@ module Saseo
|
|
27
27
|
Saseo::Config::Defaults.constants.each do |c|
|
28
28
|
attr_symbol = c.downcase.to_sym
|
29
29
|
base.send(:attr_writer, attr_symbol)
|
30
|
+
|
31
|
+
#TODO base.send(:define_method)
|
30
32
|
base.class_eval %Q{
|
31
33
|
def #{attr_symbol}
|
32
34
|
unless defined? @#{attr_symbol}
|
data/lib/saseo/config.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_record/base'
|
2
|
+
require 'saseo/whodunnit'
|
2
3
|
|
3
4
|
module Saseo
|
4
5
|
module Extensions
|
@@ -10,45 +11,6 @@ module Saseo
|
|
10
11
|
execute 'BEGIN'
|
11
12
|
Saseo::Whodunnit.set_db_whodunnit
|
12
13
|
end
|
13
|
-
|
14
|
-
def notify(channel, payload)
|
15
|
-
conn = instance_variable_get(:@connection)
|
16
|
-
conn.async_exec "SELECT pg_notify('#{channel}', '#{payload.to_s}')"
|
17
|
-
end
|
18
|
-
|
19
|
-
# Heavily cribbed from Sequel:
|
20
|
-
# https://github.com/jeremyevans/sequel/blob/c6678741ce34aac52cff966ff6a6288ccb8d5b75/lib/sequel/adapters/postgres.rb#L440
|
21
|
-
def listen(channels:, after_listen: nil, timeout: nil, loop: false, &block)
|
22
|
-
if loop && !block
|
23
|
-
raise ArgumentError, 'calling #listen with :loop requires a block'
|
24
|
-
end
|
25
|
-
channels = Array(channels)
|
26
|
-
|
27
|
-
timeout_block = timeout.respond_to?(:call) ? timeout : proc { timeout }
|
28
|
-
loop_callable = loop.respond_to?(:call)
|
29
|
-
begin
|
30
|
-
conn = instance_variable_get(:@connection)
|
31
|
-
channels.each do |channel|
|
32
|
-
conn.async_exec "LISTEN \"#{channel}\""
|
33
|
-
::ActiveRecord::Base.logger.try(:debug) { "listening to #{channel}..." }
|
34
|
-
|
35
|
-
end
|
36
|
-
after_listen.call(conn) if after_listen
|
37
|
-
|
38
|
-
if loop
|
39
|
-
catch(:stop) do
|
40
|
-
loop do
|
41
|
-
conn.wait_for_notify(timeout_block.call, &block)
|
42
|
-
loop.call(conn) if loop_callable
|
43
|
-
end
|
44
|
-
end
|
45
|
-
else
|
46
|
-
conn.wait_for_notify(timeout_block.call, &block)
|
47
|
-
end
|
48
|
-
ensure
|
49
|
-
conn.async_exec 'UNLISTEN *'
|
50
|
-
end
|
51
|
-
end
|
52
14
|
end
|
53
15
|
end
|
54
16
|
end
|
@@ -26,7 +26,7 @@ module Saseo
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def persist!(message)
|
29
|
-
logger.debug { "
|
29
|
+
logger.debug { "received source version for persistence: #{message.id}" }
|
30
30
|
version = Saseo::Models::Version.new
|
31
31
|
|
32
32
|
version_attributes.each do |attr|
|
@@ -37,8 +37,13 @@ module Saseo
|
|
37
37
|
version.old_data = message.old_data && Oj.dump(message.old_data)
|
38
38
|
version.new_data = message.new_data && Oj.dump(message.new_data)
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
begin
|
41
|
+
logger.debug { version.attributes }
|
42
|
+
version.save!
|
43
|
+
logger.debug { "saved version: #{message.id}" }
|
44
|
+
rescue ActiveRecord::RecordNotUnique => e
|
45
|
+
Philotic::Message.publish({philotic_message_type: :'saseo.error.duplicate_record'}, version.attributes)
|
46
|
+
end
|
42
47
|
end
|
43
48
|
end
|
44
49
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
require 'saseo/extensions/active_record'
|
3
1
|
require 'saseo/config'
|
4
2
|
require 'saseo/publishing/data_change_message'
|
5
3
|
require 'saseo/models/source/version'
|
@@ -9,47 +7,32 @@ module Saseo
|
|
9
7
|
module Publishing
|
10
8
|
class Publisher
|
11
9
|
|
12
|
-
|
10
|
+
attr_accessor :batch_size
|
13
11
|
attr_writer :logger
|
14
12
|
|
15
|
-
def initialize(
|
16
|
-
|
13
|
+
def initialize(batch_size: nil)
|
14
|
+
batch_size ||= Saseo.config.publisher_batch_size
|
15
|
+
self.batch_size = batch_size
|
17
16
|
end
|
18
17
|
|
19
18
|
def logger
|
20
19
|
@logger ||= Logger.new(STDOUT)
|
21
20
|
end
|
22
21
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
channels
|
22
|
+
def publish_batch
|
23
|
+
Saseo::Models::Source::Version.transaction do
|
24
|
+
ids = []
|
25
|
+
Saseo::Models::Source::Version.lock.limit(batch_size).each do |record|
|
26
|
+
Saseo::Publishing::DataChangeMessage.publish(record)
|
27
|
+
logger.debug { "published source version: #{record.id}" }
|
28
|
+
ids << record.id
|
32
29
|
end
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
30
|
+
Saseo::Models::Source::Version.delete_all(id: ids)
|
31
|
+
logger.debug { "deleted source versions: #{ids.count}" } if ids.count > 0
|
37
32
|
|
38
|
-
def run(channels: :all, loop: true, timeout: nil)
|
39
|
-
self.channels = channels
|
40
|
-
db_connection.listen channels: self.channels, loop: loop, timeout: timeout do |channel, pid, payload|
|
41
|
-
uuid = payload
|
42
|
-
logger.debug { "received NOTIFY for source version: #{uuid}" }
|
43
|
-
|
44
|
-
record = Saseo::Models::Source::Version.find(uuid)
|
45
|
-
Saseo::Publishing::DataChangeMessage.publish(record)
|
46
|
-
record.delete
|
47
|
-
logger.debug { "deleted source version: #{uuid}" }
|
48
33
|
end
|
49
|
-
|
50
|
-
|
51
|
-
def db_connection
|
52
|
-
Saseo::Models::Source::Base.connection
|
34
|
+
rescue => e
|
35
|
+
logger.error { "Saseo publishing error: #{e.class} - #{e.message} at #{e.backtrace}" }
|
53
36
|
end
|
54
37
|
end
|
55
38
|
end
|
data/lib/saseo/version.rb
CHANGED
data/saseo.example.yml
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
defaults: &defaults
|
2
|
-
|
3
|
-
|
2
|
+
publisher_batch_size: 1000
|
3
|
+
source_database_url: postgres://user:pass@host:port/source
|
4
|
+
source_database_config_path: /path/to/source/db/config
|
5
|
+
database_url: postgres://user:pass@host:port/saseo
|
6
|
+
source_database_config_path: /path/to/saseo/db/config
|
7
|
+
table_name: saseo_audit_versions
|
8
|
+
source_table_schema: audits
|
9
|
+
source_table_name: audits
|
4
10
|
|
5
11
|
development:
|
6
12
|
<<: *defaults
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saseo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Keyes
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|