seapig-postgresql-notifier 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 50448368cc1de622442aaaf0b5bfcc58be12e641
4
+ data.tar.gz: 27cbd3f1ba86bdd1dc0e8d2aee2731368eefaa6a
5
+ SHA512:
6
+ metadata.gz: 2113ccfffa3ee07c043c602704beca2b2d4124ecdc703791fde870883e2abbf6e231400628a0980cd5fb72b44dbb34c085f9cac8cd954c5ffa1f3b6f136182f1
7
+ data.tar.gz: 579dfa4bfdf826fec17104961312228cfadcd07239f760e3c6ff4a24416eb94445ad6bcc3acaece8b02e6e552aaa937bc6990e4f0f73194632f7e8b4fb4e3fc1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015-2017 yunta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,30 @@
1
+ class SeapigDependency < ActiveRecord::Base
2
+
3
+ OBJECT_PREFIX = "Postgres::"
4
+
5
+
6
+ def self.bump(*names) #FIXME: mass upsert / PG 9.5
7
+ versions = {}
8
+ self.transaction {
9
+ names.map { |name| #FIXME: race
10
+ value = self.find_by_sql(["UPDATE seapig_dependencies SET current_version = nextval('seapig_dependency_version_seq'), updated_at = now() WHERE name = ? RETURNING current_version", name])
11
+ value = self.find_by_sql(["INSERT INTO seapig_dependencies(name, current_version, reported_version, created_at, updated_at) VALUES (?,nextval('seapig_dependency_version_seq'),0,now(),now()) RETURNING current_version",name]) if value.size == 0
12
+ versions[SeapigDependency::OBJECT_PREFIX+name] = value[0].current_version
13
+ }
14
+ connection.instance_variable_get(:@connection).exec("NOTIFY seapig_dependency_changed")
15
+ }
16
+ versions
17
+ end
18
+
19
+
20
+ def self.version(name)
21
+ self.versions(name)[SeapigDependency::OBJECT_PREFIX+name]
22
+ end
23
+
24
+
25
+ def self.versions(*names)
26
+ self.find_by_sql(["SELECT names.name, COALESCE(sd.current_version,0) AS current_version FROM (SELECT unnest(ARRAY[?]) AS name) AS names LEFT OUTER JOIN seapig_dependencies AS sd ON names.name = sd.name", names]).map { |name| [SeapigDependency::OBJECT_PREFIX+name.name,name.current_version] }.to_h
27
+ end
28
+
29
+
30
+ end
@@ -0,0 +1,78 @@
1
+ #!/bin/env ruby
2
+
3
+ require 'seapig-client'
4
+ require 'active_record'
5
+ require 'slop'
6
+ require 'yaml'
7
+
8
+ require_relative '../app/models/seapig_dependency.rb'
9
+
10
+ STDOUT.sync = true
11
+
12
+ OPTIONS = Slop.parse { |o|
13
+ o.string '-c', '--connect', "Seapig server address (default: ws://127.0.0.1:3001)", default: "ws://127.0.0.1:3001"
14
+ o.array '-i', '--intervals', 'List of durations for interval objects (e.g. 1,60,3600)', default: ""
15
+ o.string '-d', '--database-url', 'Database URL (e.g. postgres://USER:PASS@PGHOST/DBNAME)'
16
+ o.string '-e', '--environment' , 'Rails environment to use when loading database config from config/database.yml'
17
+ o.on '-h', '--help' do puts o; exit end
18
+ }
19
+
20
+ if (not OPTIONS["database-url"]) and (not File.exist?("config/database.yml")) then puts "Either -d or config/database.yml is needed"; exit end
21
+ database_config = (OPTIONS["database-url"] or YAML.load_file("config/database.yml")[(OPTIONS["environment"] or ENV["RAILS_ENV"] or "development")])
22
+ ActiveRecord::Base.establish_connection(database_config)
23
+
24
+
25
+ EM.run {
26
+
27
+ client = SeapigClient.new(OPTIONS["connect"], name: 'notifier')
28
+ master_object = client.master(SeapigDependency::OBJECT_PREFIX+"*")
29
+ master_object.onproduce { |child|
30
+ version = (SeapigDependency.version(child.id[SeapigDependency::OBJECT_PREFIX.size .. -1]) or 0)
31
+ child.set(version: version)
32
+ puts 'Dependency version produced: %30s:%-10s'%[child.id,version]
33
+ }
34
+
35
+
36
+ on_database_change = Proc.new {
37
+ next if not client.connected
38
+ SeapigDependency.where("current_version != reported_version").each { |seapig_dependency|
39
+ puts "Dependency version changed: %30s:%-10s"%[seapig_dependency.name,seapig_dependency.current_version]
40
+ master_object[SeapigDependency::OBJECT_PREFIX+seapig_dependency.name].set(version: seapig_dependency.current_version)
41
+ seapig_dependency.reported_version = seapig_dependency.current_version
42
+ seapig_dependency.save!
43
+ }
44
+ }
45
+
46
+
47
+ Thread.new {
48
+ begin
49
+ ActiveRecord::Base.connection_pool.with_connection { |connection|
50
+ connection = connection.instance_variable_get(:@connection)
51
+ connection.exec("LISTEN seapig_dependency_changed")
52
+ loop {
53
+ connection.wait_for_notify { |channel, pid, payloads|
54
+ EM.schedule(on_database_change)
55
+ }
56
+ }
57
+ }
58
+ rescue Exception => e
59
+ puts "Exception in database thread"
60
+ p e
61
+ EM.schedule {
62
+ client.disconnect
63
+ EM.stop
64
+ }
65
+ end
66
+ }
67
+
68
+
69
+ OPTIONS["intervals"].split(',').each { |interval|
70
+ seapig = client.master('Seconds:'+interval)
71
+ EM.add_periodic_timer(interval.to_i) {
72
+ seapig.set(version: Time.new.to_i/interval.to_i)
73
+ }
74
+ }
75
+
76
+ EM.schedule on_database_change
77
+
78
+ }
@@ -0,0 +1,16 @@
1
+ class CreateSeapigVersions < ActiveRecord::Migration
2
+ def change
3
+ create_table :seapig_dependencies do |t|
4
+ t.text :name
5
+ t.bigint :current_version
6
+ t.bigint :reported_version
7
+
8
+ t.timestamps null: false
9
+ end
10
+
11
+ execute 'CREATE INDEX ON seapig_dependencies(name,current_version)'
12
+ execute 'CREATE INDEX ON seapig_dependencies((current_version != reported_version)) WHERE current_version != reported_version'
13
+ execute 'CREATE SEQUENCE seapig_dependency_version_seq OWNED BY seapig_dependencies.current_version'
14
+ end
15
+ end
16
+
@@ -0,0 +1,6 @@
1
+ if defined? Rails
2
+ module SeapigPostgresqlNotifier
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module SeapigPostgresqlNotifier
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "seapig-postgresql-notifier/engine"
2
+ require_relative "../app/models/seapig_dependency.rb"
3
+
4
+
5
+ module SeapigPostgresqlNotifier
6
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seapig-postgresql-notifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - yunta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: seapig-client-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: slop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: meh
56
+ email:
57
+ - maciej.blomberg@mikoton.com
58
+ executables:
59
+ - seapig-postgresql-notifier
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - MIT-LICENSE
64
+ - app/models/seapig_dependency.rb
65
+ - bin/seapig-postgresql-notifier
66
+ - db/migrate/20151228202111_create_seapig_versions.rb
67
+ - lib/seapig-postgresql-notifier.rb
68
+ - lib/seapig-postgresql-notifier/engine.rb
69
+ - lib/seapig-postgresql-notifier/version.rb
70
+ homepage: https://github.com/yunta-mb/seapig-rails
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.5.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Transient object synchronization lib - rails
94
+ test_files: []