activehook 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ec5f569ad2e4d49a1726c2d19a90ce2b7648af1f
4
- data.tar.gz: b2de4d8bc94e5ae5d52a1e377d6722196a8c7916
3
+ metadata.gz: f3a59808084220469fb34637c67bf5e9f262e631
4
+ data.tar.gz: 791adea3103be50f0b47ae4a1bcc85456271279b
5
5
  SHA512:
6
- metadata.gz: 2148e1300b59027bb0c169308a51e5cdc756f3f4f61a1478794a461fe49dec8b0459df1b8ea6950b3ce45713dbc127424ad4b300bb5b37ea968d697577bd6495
7
- data.tar.gz: 9eed68184e55a437fcece72ead80cd5a2b178d02afbd280f1ce4fdb48d935749fe2be7524e35300860a9c610a4c4ad376bdf4c8a6eb98aca3411103ddff0bb3a
6
+ metadata.gz: 40f0470b5c5239cc3f7ea56cb20c458239d72ada5180327ac45356ab32357ee0770d66a8c23691619ba4d2eeca3dff0df0e133154384803ed90189b0f450a2a9
7
+ data.tar.gz: e9cd328d156e39b4d9478fb3aa8740d5999404629ac0adae3a8c0c67b8e55071168a98ba8c7c843b6e46a34b8c9d47ac95b5d0e1dae3b920f831e605342c1524
data/Procfile ADDED
@@ -0,0 +1,2 @@
1
+ web: bundle exec activehook-app -p test/config/puma.rb
2
+ worker: bundle exec activehook-server
data/README.md CHANGED
@@ -3,7 +3,11 @@
3
3
 
4
4
  Fast and simple webhook microservice for Ruby. **Please consider it under development at the moment.**
5
5
 
6
- ActiveHook provides a scalable solution to your applications webhook sending needs. Its Redis-backed, with support for forking and threading - letting it send an enormous amount of webhooks in short order. Basically a much more focused version of a job processor such as Sidekiq, DelayedJob, Resque, etc.
6
+ ActiveHook provides a scalable solution to your applications webhook sending needs. Its Redis-backed, with support for forking and threading - letting it send an enormous amount of webhooks in short order. Basically a much more focused version of a job processor such as Sidekiq, DelayedJob, Resque, etc. It includes the following:
7
+
8
+ - A server for the purpose of sending webhooks.
9
+ - A mixin module for the purpose of recieving and validating webhooks.
10
+ - A piece of Rack middleware for the purpose of performing validation.
7
11
 
8
12
  ## Installation
9
13
 
@@ -23,38 +27,155 @@ Or install it yourself as:
23
27
 
24
28
  ## Getting Started
25
29
 
26
- Before starting, ensure you have a functioning Redis server available. ActiveHook runs as a seperate server beyond Rails, Sinatra, etc. To start the server simply type the following in your console.
30
+ Before starting, ensure you have a functioning Redis server available.
31
+
32
+ ActiveHook can be run in a few different ways.
33
+
34
+ #### Server Mode
27
35
 
28
- $ bundle exec activehook -c config/initializers/activehook.rb
36
+ In order to send webhooks, we operate ActiveHook in server mode. This will be run as a seperate service beyond your web application (Rails, Sinatra, etc). To start the server simply type the following in your console.
29
37
 
30
- By providing a path to a configuration file, we can setup ActiveHook with plain old ruby. Below is a list of currently available options:
38
+ $ bundle exec activehook-server -c config/activehook.rb
39
+
40
+ By providing a path to a configuration file, we can setup ActiveHook with plain old ruby. Below is a list of currently available server options:
31
41
 
32
42
  ```ruby
43
+ # ActiveHook server configuration
33
44
  ActiveHook.configure do |config|
34
45
  #Your redis server url
35
46
  config.redis_url = ENV['REDIS_URL']
36
47
  #The number of redis connections to provide
37
- config.redis_pool = 5
48
+ config.redis_pool = 10
38
49
  #The number of forked workers to create for the server
39
50
  config.workers = 2
40
51
  #The number of queue threads to provide for each worker
41
- config.queue_threads = 5
52
+ config.queue_threads = 2
42
53
  #The number of retry threads to provide for each worker
43
- config.retry_threads = 2
44
- #The maximum amount of retries to attempt for failed webhooks
45
- config.retry_max = 3
46
- #The amount of time between each retry attempt
47
- config.retry_time = 3600
54
+ config.retry_threads = 1
55
+ end
56
+ ```
57
+
58
+ #### App Mode
59
+
60
+ In order to create webhooks, we operate ActiveHook in app mode. Like above, we need to provide information on Redis. We will also need to provide a path in our web application that can be used for validation. With Rails, we should place this configuration with our initializers.
61
+
62
+ ```ruby
63
+ #IMPORTANT!
64
+ require 'activehook/app/base'
65
+
66
+ # ActiveHook app configuration
67
+ ActiveHook.configure do |config|
68
+ #Your redis server url
69
+ config.redis_url = ENV['REDIS_URL']
70
+ #The number of redis connections to provide
71
+ config.redis_pool = 5
72
+ #The route to our webhook validator
73
+ config.validation_path = '/hooks/validate'
48
74
  end
49
75
  ```
50
76
 
51
- Queuing a webhook for processing is easy. From within our application, all we have to do is:
77
+ With our app setup, we can create webhooks for processing. From within our application, all we have to do is:
52
78
 
53
79
  ```ruby
54
80
  ActiveHook::Hook.new(uri: 'http://example.com/webhook', payload: { msg: 'My first webhook!' })
55
81
  ```
56
82
 
57
- That's it! We provide a valid string URI, as well hash payload. ActiveHooks queue threads will then attempt to send the webhook. If the webhook fails to be delivered, it will be sent to the retry queue. Delivery will be reattempted at the specified intervals, and eventually dropped if all attempts fail.
83
+ That's it! We provide a valid string URI, as well hash payload. ActiveHooks server will then attempt to send the webhook. If the webhook fails to be delivered, it will be sent to the retry queue. Delivery will be reattempted at the specified intervals, and eventually dropped if all attempts fail.
84
+
85
+ The default setting for failed webhooks is 3 more attempts at an interval of 3600 seconds (1 hour). You can change these values by including them in your hook initialization.
86
+
87
+ ```ruby
88
+ ActiveHook::Hook.new(uri: 'http://example.com/webhook', payload: { msg: 'My first webhook!' }, retry_max: 3, retry_time: 3600)
89
+ ```
90
+
91
+ We will go over app webhook validation after the following section...
92
+
93
+ #### Client Mode
94
+
95
+ ActiveHook provides a class as well as mixin module for the purposes of recieving webhooks and performing validation on them. The class should be used for personal projects and testing, while the mixin module can be integrated with other application gems.
96
+
97
+ Using the class is easy. We should first add use the following config:
98
+
99
+ ```ruby
100
+ #IMPORTANT!
101
+ require 'activehook/client/base'
102
+
103
+ # ActiveHook client configuration
104
+ ActiveHook.configure do |config|
105
+ #Your validation uri
106
+ config.validation_uri = 'http://localhost:3000/hooks/validate'
107
+ end
108
+ ```
109
+
110
+ If we were using Rails we could then do the following:
111
+
112
+ ```ruby
113
+ class WebhooksController < ApplicationController
114
+
115
+ def create
116
+ @webhook = ActiveHook::Recieve.new(webhook_params)
117
+ if @webhook.hook_valid?
118
+ #We can now do stuff with the Hash @webhook.payload
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def webhook_params
125
+ params.require(:hook_id, :hook_key, :payload)
126
+ end
127
+ end
128
+ ```
129
+
130
+ Using the mixin module for our own classes would go like this:
131
+
132
+ ```ruby
133
+ require 'activehook/client/base'
134
+
135
+ module MyApp
136
+ class Webhook
137
+ include ActiveHook::Client::Recieve
138
+
139
+ #IMPORTANT! We will go over running the validation server next.
140
+ VALIDATION_URI = 'http://myapp.com/hooks/validate'
141
+ end
142
+ end
143
+ ```
144
+
145
+ This would allow us to perform the same validation actions as in our Rails example, except we could use:
146
+
147
+ ```ruby
148
+ @webhook = MyApp::Webhook.new(webhook_params)
149
+ if @webhook.hook_valid?
150
+ #We can now do stuff with the Hash @webhook.payload
151
+ end
152
+ ```
153
+
154
+ #### App Mode Validation
155
+
156
+ Sending webhooks is one thing - ensuring they are from who we want is another.
157
+
158
+ ActiveHook includes a piece of Rack middleware for the purpose of validation. When a client attempts to validate a webhook, they are sending a message back to your server. The message includes the hooks ID as well as key. These are are then cross-referenced. If they match, we provide the AOK.
159
+
160
+ In Rails, we would add the middleware like this:
161
+
162
+ ```ruby
163
+ # In config/application.rb
164
+ config.middleware.use ActiveHook::App::Middleware
165
+ ```
166
+
167
+ Or with Rackup files:
168
+
169
+ ```ruby
170
+ # In config.ru
171
+ use ActiveHook::App::Middleware
172
+ ```
173
+
174
+ ActiveHook also provides a straight lightweight validation microservice. This simply runs the middleware with Puma on its own.
175
+
176
+ $ bundle exec activehook-app -p config/puma.rb -c config/activehook.rb
177
+
178
+ We must provide a path to our Puma config file as well as our ActiveHook app config file. Please read more about Puma if you need help with this.
58
179
 
59
180
  ## Development
60
181
 
data/activehook.gemspec CHANGED
@@ -14,11 +14,13 @@ Gem::Specification.new do |spec|
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.executables = %w( activehook )
17
+ spec.executables = %w( activehook-server activehook-app )
18
18
  spec.require_paths = %w( lib )
19
19
 
20
- spec.add_runtime_dependency "redis", "~> 3.3"
21
- spec.add_runtime_dependency "connection_pool", "~> 2.2"
20
+ spec.add_runtime_dependency "redis", "~> 3.3"
21
+ spec.add_runtime_dependency "connection_pool", "~> 2.2"
22
+ spec.add_runtime_dependency "puma", "~> 3.4"
23
+ spec.add_runtime_dependency "rack"
22
24
  spec.add_development_dependency "bundler", "~> 1.12"
23
25
  spec.add_development_dependency "rake", "~> 10.0"
24
26
  spec.add_development_dependency "minitest", "~> 5.0"
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'activehook'
4
+ require 'activehook/app/base'
5
+
6
+ app = ActiveHook::App::Launcher.new(ARGV)
7
+ app.start
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'activehook'
4
+ require 'activehook/server/base'
5
+
6
+ server = ActiveHook::Server::Launcher.new(ARGV)
7
+ server.start
@@ -0,0 +1,17 @@
1
+ ActiveHook.mode = :app
2
+
3
+ require 'puma'
4
+ require 'rack'
5
+ require 'redis'
6
+ require 'json'
7
+ require 'connection_pool'
8
+ require 'activehook/config'
9
+ require 'activehook/log'
10
+ require 'activehook/redis'
11
+ require 'activehook/errors'
12
+ require 'activehook/hook'
13
+ require 'activehook/validate'
14
+ require 'activehook/version'
15
+ require 'activehook/app/config'
16
+ require 'activehook/app/launcher'
17
+ require 'activehook/app/middleware'
@@ -0,0 +1,17 @@
1
+ module ActiveHook
2
+ module App
3
+ class Config < ActiveHook::BaseConfig
4
+ OTHER_DEFAULTS = {
5
+ validation_path: '/hooks/validate',
6
+ creation_path: '/hooks'
7
+ }.freeze
8
+
9
+ attr_accessor :validation_path, :creation_path
10
+
11
+ def initialize
12
+ super
13
+ OTHER_DEFAULTS.each { |key, value| send("#{key}=", value) }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ require 'activehook'
2
+ require 'activehook/app/base'
3
+ require 'byebug'
4
+
5
+ use ActiveHook::App::Middleware
6
+ run -> (env) { [200, {"Content-Type" => "text/html"}, ["Hello World!"]] }
@@ -0,0 +1,51 @@
1
+ module ActiveHook
2
+ module App
3
+ # Handles the start of the ActiveHook web via command line
4
+ #
5
+ class Launcher
6
+ def initialize(argv)
7
+ @argv = argv
8
+ @puma_config = nil
9
+ end
10
+
11
+ def start
12
+ start_message
13
+ setup_options
14
+ boot_puma
15
+ end
16
+
17
+ private
18
+
19
+ def start_message
20
+ ActiveHook.log.info('ActiveHook App starting!')
21
+ ActiveHook.log.info("* Version #{VERSION}, codename: #{CODENAME}")
22
+ end
23
+
24
+ # Parses the arguments passed through the command line.
25
+ #
26
+ def setup_options
27
+ parser = OptionParser.new do |o|
28
+ o.banner = 'Usage: bundle exec bin/activehook [options]'
29
+
30
+ o.on('-c', '--config PATH', 'Load PATH for config file') do |arg|
31
+ load(arg)
32
+ ActiveHook.log.info("* App config: #{arg}")
33
+ end
34
+
35
+ o.on('-p', '--puma config PATH', 'Load PATH for puma config file') do |arg|
36
+ @puma_config = arg
37
+ ActiveHook.log.info("* Puma config: #{arg}")
38
+ end
39
+
40
+ o.on('-h', '--help', 'Prints this help') { puts o && exit }
41
+ end
42
+ parser.parse!(@argv)
43
+ end
44
+
45
+ def boot_puma
46
+ ActiveHook.log.info('* Booting Puma...')
47
+ exec("bundle exec puma -C #{@puma_config} --dir lib/activehook/app/")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ module ActiveHook
2
+ module App
3
+ class Middleware
4
+ class << self
5
+ attr_accessor :valid, :invalid, :not_created, :created
6
+ end
7
+
8
+ @invalid = ->(_env) { [400, { "Content-Type" => "application/json" }, [{ valid: false }.to_json]] }
9
+ @valid = ->(_env) { [200, { "Content-Type" => "application/json" }, [{ valid: true }.to_json]] }
10
+ @not_created = ->(_env) { [400, { "Content-Type" => "application/json" }, [{ status: false }.to_json]] }
11
+ @created = ->(_env) { [200, { "Content-Type" => "application/json" }, [{ status: true }.to_json]] }
12
+
13
+ def initialize(app)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ @env = env
19
+ @req = Rack::Request.new(env)
20
+
21
+ if validation_request? then valid?
22
+ elsif creation_request? then create?
23
+ else @app.call(@env)
24
+ end
25
+ end
26
+
27
+ def validation_request?
28
+ @req.path == ActiveHook.config.validation_path && @req.get?
29
+ end
30
+
31
+ def creation_request?
32
+ @req.path == ActiveHook.config.creation_path && @req.post?
33
+ end
34
+
35
+ def valid?
36
+ if Validation.new(@req.params).start
37
+ self.class.valid.call(@env)
38
+ else
39
+ self.class.invalid.call(@env)
40
+ end
41
+ end
42
+
43
+ def create?
44
+ if Creation.new(@req.params).start
45
+ self.class.created.call(@env)
46
+ else
47
+ self.class.not_created.call(@env)
48
+ end
49
+ end
50
+ end
51
+
52
+ Validation = Struct.new(:params) do
53
+ def start
54
+ hook = { id: params['id'].to_i, key: params['key'] }
55
+ ActiveHook::Validate.new(hook).perform
56
+ rescue
57
+ false
58
+ end
59
+ end
60
+
61
+ Creation = Struct.new(:params) do
62
+ def start
63
+ hook = { uri: params['uri'], payload: JSON.parse(params['payload']) }
64
+ ActiveHook::Hook.new(hook).perform
65
+ rescue
66
+ false
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,8 @@
1
+ ActiveHook.mode = :client
2
+
3
+ require 'uri'
4
+ require 'json'
5
+ require 'net/http'
6
+ require 'activehook/config'
7
+ require 'activehook/client/config'
8
+ require 'activehook/client/recieve'
@@ -0,0 +1,16 @@
1
+ module ActiveHook
2
+ module Client
3
+ class Config < ActiveHook::BaseConfig
4
+ OTHER_DEFAULTS = {
5
+ validation_uri: 'http://localhost:3000/hooks/validate'
6
+ }.freeze
7
+
8
+ attr_accessor :validation_uri
9
+
10
+ def initialize
11
+ super
12
+ OTHER_DEFAULTS.each { |key, value| send("#{key}=", value) }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ module ActiveHook
2
+ module Client
3
+ module Recieve
4
+
5
+ REQUEST_HEADERS = {
6
+ "Content-Type" => "application/json",
7
+ "Accept" => "application/json",
8
+ "User-Agent" => "ActiveHook/#{ActiveHook::VERSION}"
9
+ }.freeze
10
+
11
+ attr_accessor :hook_id, :hook_key
12
+ attr_reader :payload
13
+
14
+ def hook_valid?
15
+ @hook_valid ||= validate_hook
16
+ end
17
+
18
+ def payload=(payload)
19
+ @payload = JSON.parse(payload)
20
+ rescue
21
+ nil
22
+ end
23
+
24
+ def validated_payload
25
+ raise StandardError, 'Webhook is invalid.' unless hook_valid?
26
+ @payload
27
+ end
28
+
29
+ private
30
+
31
+ def hook_uri
32
+ @hook_uri ||= URI.parse(self.class::VALIDATION_URI)
33
+ end
34
+
35
+ def validate_hook
36
+ http = Net::HTTP.new(hook_uri.host, hook_uri.port)
37
+ response = http.post(hook_uri.path, hook_json, REQUEST_HEADERS)
38
+ response.code.to_i == 200 ? true : false
39
+ rescue
40
+ false
41
+ end
42
+
43
+ def hook_json
44
+ { id: @hook_id,
45
+ key: @hook_key }.to_json
46
+ end
47
+ end
48
+ end
49
+
50
+ class Recieve
51
+ include ActiveHook::Client::Recieve
52
+
53
+ VALIDATION_URI = (ActiveHook.config.validation_uri).freeze
54
+ end
55
+ end
@@ -6,7 +6,17 @@ module ActiveHook
6
6
  end
7
7
 
8
8
  def config
9
- @config ||= Config.new
9
+ @config ||= build_config
10
+ end
11
+
12
+ def build_config
13
+ klass =
14
+ case ActiveHook.mode
15
+ when :server then ActiveHook::Server::Config
16
+ when :client then ActiveHook::Client::Config
17
+ else ActiveHook::App::Config
18
+ end
19
+ klass.new
10
20
  end
11
21
 
12
22
  def reset
@@ -15,33 +25,22 @@ module ActiveHook
15
25
  end
16
26
  end
17
27
 
18
- class Config
19
- DEFAULTS = {
28
+ class BaseConfig
29
+ BASE_DEFAULTS = {
20
30
  redis_url: ENV['REDIS_URL'],
21
- redis_pool: 5,
22
- workers: 2,
23
- queue_threads: 4,
24
- retry_threads: 2,
25
- retry_max: 3,
26
- retry_time: 3600,
31
+ redis_pool: 5
27
32
  }.freeze
28
33
 
29
- attr_accessor :redis_url, :redis_pool, :retry_max, :retry_time,
30
- :workers, :queue_threads, :retry_threads
34
+ attr_accessor :redis_url, :redis_pool
31
35
 
32
36
  def initialize
33
- DEFAULTS.each { |key, value| send("#{key}=", value) }
34
- end
35
-
36
- def retry_max_time
37
- @retry_max_time ||= retry_max * retry_time
37
+ BASE_DEFAULTS.each { |key, value| send("#{key}=", value) }
38
38
  end
39
39
 
40
- def worker_options
40
+ def redis
41
41
  {
42
- worker_count: workers,
43
- queue_threads: queue_threads,
44
- retry_threads: retry_threads
42
+ size: redis_pool,
43
+ url: redis_url
45
44
  }
46
45
  end
47
46
  end
@@ -4,5 +4,7 @@ module ActiveHook
4
4
  class Hook < StandardError; end
5
5
  class HTTP < StandardError; end
6
6
  class Send < StandardError; end
7
+ class Server < StandardError; end
8
+ class Worker < StandardError; end
7
9
  end
8
10
  end
@@ -2,7 +2,7 @@ require 'securerandom'
2
2
 
3
3
  module ActiveHook
4
4
  class Hook
5
- attr_accessor :uri, :payload, :id, :created_at, :retry_at, :fail_at
5
+ attr_accessor :uri, :payload, :id, :key, :retry_max, :retry_time, :created_at
6
6
 
7
7
  def initialize(options = {})
8
8
  options = defaults.merge(options)
@@ -10,47 +10,65 @@ module ActiveHook
10
10
  end
11
11
 
12
12
  def perform
13
- valid?
13
+ validate!
14
14
  ActiveHook.redis.with do |conn|
15
- conn.pipelined do
16
- conn.lpush('ah:queue', to_json)
17
- conn.incr('ah:total_queued')
18
- end
15
+ @id = conn.incr('ah:total_queued')
16
+ conn.lpush('ah:queue', to_json)
17
+ conn.zadd('ah:validation', @id, @key)
19
18
  end
20
19
  end
21
20
 
22
- def bump_retry
23
- @retry_at = Time.now.to_i + ActiveHook.config.retry_time
21
+ def retry?
22
+ fail_at > Time.now.to_i
24
23
  end
25
24
 
26
- def retry?
27
- @fail_at.to_i > Time.now.to_i
25
+ def retry_at
26
+ Time.now.to_i + @retry_time.to_i
27
+ end
28
+
29
+ def fail_at
30
+ @created_at.to_i + retry_max_time
31
+ end
32
+
33
+ def retry_max_time
34
+ @retry_time.to_i * @retry_max.to_i
28
35
  end
29
36
 
30
37
  def to_json
31
38
  { id: @id,
39
+ key: @key,
32
40
  created_at: @created_at,
33
- retry_at: @retry_at,
34
- fail_at: @fail_at,
41
+ retry_time: @retry_time,
42
+ retry_max: @retry_max,
35
43
  uri: @uri,
36
44
  payload: @payload }.to_json
37
45
  end
38
46
 
47
+ def secure_payload
48
+ { hook_id: @id,
49
+ hook_key: @key,
50
+ payload: @payload }.to_json
51
+ end
52
+
53
+ def valid?
54
+ HookValidator.new(id: @id, key: @key).server_valid?
55
+ end
56
+
39
57
  private
40
58
 
41
59
  def defaults
42
- { id: SecureRandom.uuid,
60
+ { key: SecureRandom.uuid,
43
61
  created_at: Time.now.to_i,
44
- retry_at: Time.now.to_i + ActiveHook.config.retry_time,
45
- fail_at: Time.now.to_i + ActiveHook.config.retry_max_time }
62
+ retry_time: 3600,
63
+ retry_max: 3 }
46
64
  end
47
65
 
48
- def valid?
66
+ def validate!
49
67
  raise Errors::Hook, 'Payload must be a Hash.' unless @payload.is_a?(Hash)
50
68
  raise Errors::Hook, 'URI is not a valid format.' unless @uri =~ /\A#{URI::regexp}\z/
51
69
  raise Errors::Hook, 'Created at must be an Integer.' unless @created_at.is_a?(Integer)
52
- raise Errors::Hook, 'Retry at must be an Integer.' unless @retry_at.is_a?(Integer)
53
- raise Errors::Hook, 'Fail at must be an Integer.' unless @fail_at.is_a?(Integer)
70
+ raise Errors::Hook, 'Retry time must be an Integer.' unless @retry_time.is_a?(Integer)
71
+ raise Errors::Hook, 'Retry max must be an Integer.' unless @retry_max.is_a?(Integer)
54
72
  end
55
73
  end
56
74
  end
@@ -13,7 +13,7 @@ module ActiveHook
13
13
  def initialize
14
14
  @log = ::Logger.new(STDOUT)
15
15
  @log.formatter = proc do |_severity, datetime, _progname, msg|
16
- "[ #{datetime} ] #{msg}\n"
16
+ "#{msg}\n"
17
17
  end
18
18
  end
19
19
 
@@ -1,5 +1,3 @@
1
- require 'redis'
2
-
3
1
  module ActiveHook
4
2
  class << self
5
3
  attr_reader :connection_pool