subserver 0.1.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.
@@ -0,0 +1,24 @@
1
+ module Subserver
2
+ class MessageLogger
3
+
4
+ def call(message)
5
+ start = Time.now
6
+ logger.info("start")
7
+ yield
8
+ logger.info("done: #{elapsed(start)} sec")
9
+ rescue Exception
10
+ logger.info("fail: #{elapsed(start)} sec")
11
+ raise
12
+ end
13
+
14
+ private
15
+
16
+ def elapsed(start)
17
+ (Time.now - start).round(3)
18
+ end
19
+
20
+ def logger
21
+ Subserver.logger
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Subserver
3
+ module Middleware
4
+ class ActiveRecord
5
+
6
+ def initialize
7
+ # With Rails 5+ we must use the Reloader **always**.
8
+ # The reloader handles code loading and db connection management.
9
+ if defined?(::Rails) && ::Rails::VERSION::MAJOR >= 5
10
+ raise ArgumentError, "Rails 5 no longer needs or uses the ActiveRecord middleware."
11
+ end
12
+ end
13
+
14
+ def call(*args)
15
+ yield
16
+ ensure
17
+ ::ActiveRecord::Base.clear_active_connections!
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+ module Subserver
3
+ # Middleware is code configured to run before/after
4
+ # a message is processed. It is patterned after Rack
5
+ # middleware.
6
+ #
7
+ # To modify middleware for the server, just call
8
+ # with another block:
9
+ #
10
+ # Subserver.configure do |config|
11
+ # config.middleware do |chain|
12
+ # chain.add MyServerHook
13
+ # chain.remove ActiveRecord
14
+ # end
15
+ # end
16
+ #
17
+ # To insert immediately preceding another entry:
18
+ #
19
+ # Subserver.configure do |config|
20
+ # config.middleware do |chain|
21
+ # chain.insert_before ActiveRecord, MyServerHook
22
+ # end
23
+ # end
24
+ #
25
+ # To insert immediately after another entry:
26
+ #
27
+ # Subserver.configure do |config|
28
+ # config.middleware do |chain|
29
+ # chain.insert_after ActiveRecord, MyServerHook
30
+ # end
31
+ # end
32
+ #
33
+ # This is an example of a minimal server middleware:
34
+ #
35
+ # class MyServerHook
36
+ # def call(subscriber_class, message)
37
+ # puts "Before work"
38
+ # yield
39
+ # puts "After work"
40
+ # end
41
+ # end
42
+ #
43
+ #
44
+ module Middleware
45
+ class Chain
46
+ include Enumerable
47
+ attr_reader :entries
48
+
49
+ def initialize_copy(copy)
50
+ copy.instance_variable_set(:@entries, entries.dup)
51
+ end
52
+
53
+ def each(&block)
54
+ entries.each(&block)
55
+ end
56
+
57
+ def initialize
58
+ @entries = []
59
+ yield self if block_given?
60
+ end
61
+
62
+ def remove(klass)
63
+ entries.delete_if { |entry| entry.klass == klass }
64
+ end
65
+
66
+ def add(klass, *args)
67
+ remove(klass) if exists?(klass)
68
+ entries << Entry.new(klass, *args)
69
+ end
70
+
71
+ def prepend(klass, *args)
72
+ remove(klass) if exists?(klass)
73
+ entries.insert(0, Entry.new(klass, *args))
74
+ end
75
+
76
+ def insert_before(oldklass, newklass, *args)
77
+ i = entries.index { |entry| entry.klass == newklass }
78
+ new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
79
+ i = entries.index { |entry| entry.klass == oldklass } || 0
80
+ entries.insert(i, new_entry)
81
+ end
82
+
83
+ def insert_after(oldklass, newklass, *args)
84
+ i = entries.index { |entry| entry.klass == newklass }
85
+ new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
86
+ i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
87
+ entries.insert(i+1, new_entry)
88
+ end
89
+
90
+ def exists?(klass)
91
+ any? { |entry| entry.klass == klass }
92
+ end
93
+
94
+ def retrieve
95
+ map(&:make_new)
96
+ end
97
+
98
+ def clear
99
+ entries.clear
100
+ end
101
+
102
+ def invoke(*args)
103
+ chain = retrieve.dup
104
+ traverse_chain = lambda do
105
+ if chain.empty?
106
+ yield
107
+ else
108
+ chain.shift.call(*args, &traverse_chain)
109
+ end
110
+ end
111
+ traverse_chain.call
112
+ end
113
+ end
114
+
115
+ class Entry
116
+ attr_reader :klass
117
+
118
+ def initialize(klass, *args)
119
+ @klass = klass
120
+ @args = args
121
+ end
122
+
123
+ def make_new
124
+ @klass.new(*@args)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,20 @@
1
+ require "google/cloud/pubsub"
2
+
3
+ module Subserver
4
+ module Pubsub
5
+ def self.client
6
+ defined?(@client) ? @client : initialize_client
7
+ end
8
+
9
+ def self.initialize_client
10
+ @client = Google::Cloud::Pubsub.new(
11
+ project_id: options[:project_id],
12
+ credentials: File.expand_path(options[:credentials])
13
+ )
14
+ end
15
+
16
+ def self.options
17
+ Subserver.options
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,57 @@
1
+ module Subserver
2
+ class Rails < ::Rails::Engine
3
+ # We need to setup this up before any application configuration which might
4
+ # change Subserver middleware.
5
+ #
6
+ # This hook happens after `Rails::Application` is inherited within
7
+ # config/application.rb and before config is touched, usually within the
8
+ # class block. Definitely before config/environments/*.rb and
9
+ # config/initializers/*.rb.
10
+ config.before_configuration do
11
+ if ::Rails::VERSION::MAJOR < 5 && defined?(::ActiveRecord)
12
+ Subserver.middleware do |chain|
13
+ require 'subserver/middleware/active_record'
14
+ chain.add Subserver::Middleware::ActiveRecord
15
+ end
16
+ end
17
+ end
18
+
19
+ config.after_initialize do
20
+ # This hook happens after all initializers are run, just before returning
21
+ # from config/environment.rb back to subserver/cli.rb.
22
+ # We have to add the reloader after initialize to see if cache_classes has
23
+ # been turned on.
24
+ #
25
+ Subserver.configure do |_|
26
+
27
+ Subserver.options[:subscriber_dir] = ::Rails.root.join('app', 'subscribers')
28
+
29
+ if ::Rails::VERSION::MAJOR >= 5
30
+ Subserver.options[:reloader] = Subserver::Rails::Reloader.new
31
+ end
32
+ end
33
+ end
34
+
35
+ class Reloader
36
+ def initialize(app = ::Rails.application)
37
+ @app = app
38
+ end
39
+
40
+ def call
41
+ @app.reloader.wrap do
42
+ yield
43
+ end
44
+ end
45
+
46
+ def inspect
47
+ "#<Subserver::Rails::Reloader @app=#{@app.class.name}>"
48
+ end
49
+ end
50
+ end if defined?(::Rails)
51
+ end
52
+
53
+ if defined?(::Rails) && ::Rails::VERSION::MAJOR < 4
54
+ $stderr.puts("**************************************************")
55
+ $stderr.puts("WARNING: Subserver is not supported on Rails < 4. Please Update to a newer version of Rails.")
56
+ $stderr.puts("**************************************************")
57
+ end
@@ -0,0 +1,25 @@
1
+ module Subserver
2
+ module Subscriber
3
+
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ def logger
9
+ Subserver.logger
10
+ end
11
+
12
+ module ClassMethods
13
+ @subserver_options
14
+
15
+ def subserver_options(opts={})
16
+ (@subserver_options ||= Subserver.default_subscriber_options).merge!(opts)
17
+ end
18
+
19
+ def get_subserver_options
20
+ @subserver_options
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ require 'socket'
3
+ require 'securerandom'
4
+ require 'subserver/exception_handler'
5
+
6
+ module Subserver
7
+ ##
8
+ # This module is part of Subserver core and not intended for extensions.
9
+ #
10
+ module Util
11
+ include ExceptionHandler
12
+
13
+ EXPIRY = 60 * 60 * 24
14
+
15
+ def watchdog(last_words)
16
+ yield
17
+ rescue Exception => ex
18
+ handle_exception(ex, { context: last_words })
19
+ raise ex
20
+ end
21
+
22
+ def safe_thread(name, &block)
23
+ Thread.new do
24
+ Thread.current['subserver_label'] = name
25
+ watchdog(name, &block)
26
+ end
27
+ end
28
+
29
+ def logger
30
+ Subserver.logger
31
+ end
32
+
33
+ def hostname
34
+ ENV['DYNO'] || Socket.gethostname
35
+ end
36
+
37
+ def process_nonce
38
+ @@process_nonce ||= SecureRandom.hex(6)
39
+ end
40
+
41
+ def identity
42
+ @@identity ||= "#{hostname}:#{$$}:#{process_nonce}"
43
+ end
44
+
45
+ def fire_event(event, options={})
46
+ reverse = options[:reverse]
47
+ reraise = options[:reraise]
48
+
49
+ arr = Subserver.options[:lifecycle_events][event]
50
+ arr.reverse! if reverse
51
+ arr.each do |block|
52
+ begin
53
+ block.call
54
+ rescue => ex
55
+ handle_exception(ex, { context: "Exception during Subserver lifecycle event.", event: event })
56
+ raise ex if reraise
57
+ end
58
+ end
59
+ arr.clear
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module Subserver
3
+ VERSION = "0.1.0"
4
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: subserver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Scott Hill
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-08-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: google-cloud-pubsub
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.31'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.31.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.31'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.31.0
33
+ description: Subserver is a background server process for processing messages from
34
+ Google Pub/Sub.
35
+ email:
36
+ executables:
37
+ - subserver
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - CHANGELOG.md
42
+ - CONTRIBUTING.md
43
+ - LICENSE
44
+ - README.md
45
+ - bin/subserver
46
+ - lib/subserver.rb
47
+ - lib/subserver/cli.rb
48
+ - lib/subserver/exception_handler.rb
49
+ - lib/subserver/health.rb
50
+ - lib/subserver/launcher.rb
51
+ - lib/subserver/listener.rb
52
+ - lib/subserver/logging.rb
53
+ - lib/subserver/manager.rb
54
+ - lib/subserver/message_logger.rb
55
+ - lib/subserver/middleware/active_record.rb
56
+ - lib/subserver/middleware/chain.rb
57
+ - lib/subserver/pubsub.rb
58
+ - lib/subserver/rails.rb
59
+ - lib/subserver/subscriber.rb
60
+ - lib/subserver/util.rb
61
+ - lib/subserver/version.rb
62
+ homepage: https://github.com/lifechurch/subserver/
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.3.1
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.5.2.3
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Simple background server process for Google Pub/Sub.
86
+ test_files: []