lambda_punch 0.0.4 → 1.0.0

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
  SHA256:
3
- metadata.gz: 7efb456be5902ca1efefb893af810b03b2f6f0590f2eb894c7ed89c8d4a2b277
4
- data.tar.gz: 81141dbc0db7a3f26fa9bdd0407d8b582ea8f5868919b7bc914a687ef6d46885
3
+ metadata.gz: eb70c0a40e9a90e863ea43325168469cfefb1a1c6825a9eced81de68314674c6
4
+ data.tar.gz: d31d67d900e3021aec70b88ce46fd119f11a1ee5e7b7f14f0c7fcee58a57a053
5
5
  SHA512:
6
- metadata.gz: 4ae480c414a1be271caf1340c5ccc4b10c57dc1c5dad7fa38dc35009caba6b1c3e63477b271e1a9b751eacccfc38ac72e7dea776c502b9ae19cc3224a611b572
7
- data.tar.gz: 92d293001511ad47ba906fe796470fbef185f90c151efb0312574beaace8d80229fabc4b72d73a74219e5d49bcc9076546d308c7ea240d5d04f6032c69c19e4c
6
+ metadata.gz: d92d93bd3e0dc94f80b73409181ee1702f44d3b4b77161861da63d10852134413de9e137f33e4848b3cbb83a0ca457a2d84de79643461a3fe8ecb42b3f4a95ed
7
+ data.tar.gz: e374f48513db58003daa361352cdbfa499048e5006b578cf36d97d043a3973dd0f7410e18a668afc2d7f03d683b562a867d69e0ea0ec90c3041491808e2afc4e
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
1
  /.bundle/*
2
- /vendor/bunlde/*
2
+ /vendor/bundle
3
3
  /.yardoc
4
4
  /_yardoc/
5
5
  /coverage/
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## [1.0.0] - 2021-07-05
2
+
3
+ ### Added
4
+
5
+ - Rails ActiveJob support.
6
+
7
+ ## [0.0.8] - 2021-06-28
8
+
9
+ - Guard against early notifier.
10
+
11
+ ## [0.0.7] - 2021-06-28
12
+
13
+ - Fix queue logger.
14
+
15
+ ## [0.0.6] - 2021-06-28
16
+
17
+ - Ensure Queue is always callable.
18
+ - Change default log level to `error`.
19
+
20
+ ## [0.0.5] - 2021-06-28
21
+
22
+ - Ensure Queue is always present.
23
+
1
24
  ## [0.0.4] - 2021-06-28
2
25
 
3
26
  - Fix install rake bug. Non-Rails rake doc.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lambda_punch (0.0.4)
4
+ lambda_punch (1.0.0)
5
5
  concurrent-ruby
6
6
  rake
7
7
  rb-inotify
@@ -10,13 +10,142 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
+ actioncable (6.1.4)
14
+ actionpack (= 6.1.4)
15
+ activesupport (= 6.1.4)
16
+ nio4r (~> 2.0)
17
+ websocket-driver (>= 0.6.1)
18
+ actionmailbox (6.1.4)
19
+ actionpack (= 6.1.4)
20
+ activejob (= 6.1.4)
21
+ activerecord (= 6.1.4)
22
+ activestorage (= 6.1.4)
23
+ activesupport (= 6.1.4)
24
+ mail (>= 2.7.1)
25
+ actionmailer (6.1.4)
26
+ actionpack (= 6.1.4)
27
+ actionview (= 6.1.4)
28
+ activejob (= 6.1.4)
29
+ activesupport (= 6.1.4)
30
+ mail (~> 2.5, >= 2.5.4)
31
+ rails-dom-testing (~> 2.0)
32
+ actionpack (6.1.4)
33
+ actionview (= 6.1.4)
34
+ activesupport (= 6.1.4)
35
+ rack (~> 2.0, >= 2.0.9)
36
+ rack-test (>= 0.6.3)
37
+ rails-dom-testing (~> 2.0)
38
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
39
+ actiontext (6.1.4)
40
+ actionpack (= 6.1.4)
41
+ activerecord (= 6.1.4)
42
+ activestorage (= 6.1.4)
43
+ activesupport (= 6.1.4)
44
+ nokogiri (>= 1.8.5)
45
+ actionview (6.1.4)
46
+ activesupport (= 6.1.4)
47
+ builder (~> 3.1)
48
+ erubi (~> 1.4)
49
+ rails-dom-testing (~> 2.0)
50
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
51
+ activejob (6.1.4)
52
+ activesupport (= 6.1.4)
53
+ globalid (>= 0.3.6)
54
+ activemodel (6.1.4)
55
+ activesupport (= 6.1.4)
56
+ activerecord (6.1.4)
57
+ activemodel (= 6.1.4)
58
+ activesupport (= 6.1.4)
59
+ activestorage (6.1.4)
60
+ actionpack (= 6.1.4)
61
+ activejob (= 6.1.4)
62
+ activerecord (= 6.1.4)
63
+ activesupport (= 6.1.4)
64
+ marcel (~> 1.0.0)
65
+ mini_mime (>= 1.1.0)
66
+ activesupport (6.1.4)
67
+ concurrent-ruby (~> 1.0, >= 1.0.2)
68
+ i18n (>= 1.6, < 2)
69
+ minitest (>= 5.1)
70
+ tzinfo (~> 2.0)
71
+ zeitwerk (~> 2.3)
72
+ builder (3.2.4)
73
+ coderay (1.1.3)
13
74
  concurrent-ruby (1.1.9)
75
+ crass (1.0.6)
76
+ erubi (1.10.0)
14
77
  ffi (1.15.3)
78
+ globalid (0.4.2)
79
+ activesupport (>= 4.2.0)
80
+ i18n (1.8.10)
81
+ concurrent-ruby (~> 1.0)
82
+ loofah (2.10.0)
83
+ crass (~> 1.0.2)
84
+ nokogiri (>= 1.5.9)
85
+ mail (2.7.1)
86
+ mini_mime (>= 0.1.1)
87
+ marcel (1.0.1)
88
+ method_source (1.0.0)
89
+ mini_mime (1.1.0)
15
90
  minitest (5.14.4)
91
+ minitest-focus (1.3.1)
92
+ minitest (>= 4, < 6)
93
+ nio4r (2.5.7)
94
+ nokogiri (1.11.7-x86_64-darwin)
95
+ racc (~> 1.4)
96
+ nokogiri (1.11.7-x86_64-linux)
97
+ racc (~> 1.4)
98
+ pry (0.14.1)
99
+ coderay (~> 1.1)
100
+ method_source (~> 1.0)
101
+ racc (1.5.2)
102
+ rack (2.2.3)
103
+ rack-test (1.1.0)
104
+ rack (>= 1.0, < 3)
105
+ rails (6.1.4)
106
+ actioncable (= 6.1.4)
107
+ actionmailbox (= 6.1.4)
108
+ actionmailer (= 6.1.4)
109
+ actionpack (= 6.1.4)
110
+ actiontext (= 6.1.4)
111
+ actionview (= 6.1.4)
112
+ activejob (= 6.1.4)
113
+ activemodel (= 6.1.4)
114
+ activerecord (= 6.1.4)
115
+ activestorage (= 6.1.4)
116
+ activesupport (= 6.1.4)
117
+ bundler (>= 1.15.0)
118
+ railties (= 6.1.4)
119
+ sprockets-rails (>= 2.0.0)
120
+ rails-dom-testing (2.0.3)
121
+ activesupport (>= 4.2.0)
122
+ nokogiri (>= 1.6)
123
+ rails-html-sanitizer (1.3.0)
124
+ loofah (~> 2.3)
125
+ railties (6.1.4)
126
+ actionpack (= 6.1.4)
127
+ activesupport (= 6.1.4)
128
+ method_source
129
+ rake (>= 0.13)
130
+ thor (~> 1.0)
16
131
  rake (13.0.3)
17
132
  rb-inotify (0.10.1)
18
133
  ffi (~> 1.0)
134
+ sprockets (4.0.2)
135
+ concurrent-ruby (~> 1.0)
136
+ rack (> 1, < 3)
137
+ sprockets-rails (3.2.2)
138
+ actionpack (>= 4.0)
139
+ activesupport (>= 4.0)
140
+ sprockets (>= 3.0.0)
141
+ thor (1.1.0)
19
142
  timeout (0.1.1)
143
+ tzinfo (2.0.4)
144
+ concurrent-ruby (~> 1.0)
145
+ websocket-driver (0.7.5)
146
+ websocket-extensions (>= 0.1.0)
147
+ websocket-extensions (0.1.5)
148
+ zeitwerk (2.4.2)
20
149
 
21
150
  PLATFORMS
22
151
  x86_64-darwin-19
@@ -25,6 +154,9 @@ PLATFORMS
25
154
  DEPENDENCIES
26
155
  lambda_punch!
27
156
  minitest
157
+ minitest-focus
158
+ pry
159
+ rails
28
160
  rake
29
161
 
30
162
  BUNDLED WITH
data/README.md CHANGED
@@ -72,7 +72,11 @@ end
72
72
 
73
73
  ### ActiveJob
74
74
 
75
- 🚧 COMING SOON 🚧 - A simple ActiveJob adapter...
75
+ You can use LambdaPunch with Rails' ActiveJob. **For a more robust background job solution, please consider using AWS SQS with the [Lambdakiq](https://github.com/customink/lambdakiq) gem.**
76
+
77
+ ```ruby
78
+ config.active_job.queue_adapter = :lambda_punch
79
+ ```
76
80
 
77
81
  ### Timeouts
78
82
 
@@ -80,11 +84,11 @@ Your function's timeout is the max amount to handle the request and process all
80
84
 
81
85
  If your application integrates with API Gateway (which has a 30 second timeout) then it is possible your function can be set with a higher timeout to perform background work. Since work is done after each invoke, the LambdaPunch queue should be empty when your function receives the `SHUTDOWN` event. If jobs are in the queue when this happens they will have two seconds max to work them down before being lost.
82
86
 
83
- **For a more robust background job solution, please consider using AWS SQS with the [Lambdakiq](https://github.com/customink/lambdakiq) gem. A drop-in replacement for [Sidekiq](https://github.com/mperham/sidekiq) when running Rails in AWS Lambda using the [Lamby](https://lamby.custominktech.com/) gem.**
87
+ **For a more robust background job solution, please consider using AWS SQS with the [Lambdakiq](https://github.com/customink/lambdakiq) gem.**
84
88
 
85
89
  ### Logging
86
90
 
87
- The default log level is `fatal`, so you will not see any LambdaPunch lines in your logs. However, if you want some low level debugging information on how LambdaPunch is working, you can use this environment variable to change the log level.
91
+ The default log level is `error`, so you will not see any LambdaPunch lines in your logs. However, if you want some low level debugging information on how LambdaPunch is working, you can use this environment variable to change the log level.
88
92
 
89
93
  ```yaml
90
94
  Environment:
@@ -92,6 +96,14 @@ Environment:
92
96
  LAMBDA_PUNCH_LOG_LEVEL: debug
93
97
  ```
94
98
 
99
+ ### Errors
100
+
101
+ As jobs are worked off the queue, all job errors are simply logged. If you want to customize this, you can set your own error handler.
102
+
103
+ ```ruby
104
+ LambdaPunch.error_handler = lambda { |e| ... }
105
+ ```
106
+
95
107
  ## 📊 CloudWatch Metrics
96
108
 
97
109
  When using Extensions, your function's CloudWatch `Duration` metrics will be the sum of your response time combined with your extension's execution time. For example, if your request takes `200ms` to respond but your background task takes `1000ms` your duration will be a combined `1200ms`. For more details see the _"Performance impact and extension overhead"_ section of the [Lambda Extensions API
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require "rake/testtask"
4
4
  Rake::TestTask.new(:test) do |t|
5
5
  t.libs << "test"
6
6
  t.libs << "lib"
7
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.test_files = FileList["test/cases/*_test.rb"]
8
8
  end
9
9
 
10
10
  task default: :test
data/lambda_punch.gemspec CHANGED
@@ -22,4 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "rake"
23
23
  spec.add_dependency "rb-inotify"
24
24
  spec.add_dependency "timeout"
25
+ spec.add_development_dependency "minitest-focus"
26
+ spec.add_development_dependency "pry"
27
+ spec.add_development_dependency "rails"
25
28
  end
data/lib/lambda_punch.rb CHANGED
@@ -13,7 +13,10 @@ require 'lambda_punch/server'
13
13
  require 'lambda_punch/worker'
14
14
  require 'lambda_punch/version'
15
15
  require 'lambda_punch/notifier'
16
- require 'lambda_punch/railtie' if defined?(Rails)
16
+ if defined?(Rails)
17
+ require 'lambda_punch/railtie'
18
+ require 'lambda_punch/rails/active_job'
19
+ end
17
20
 
18
21
  module LambdaPunch
19
22
 
@@ -45,6 +48,16 @@ module LambdaPunch
45
48
  Notifier.handled!(context)
46
49
  end
47
50
 
51
+ def error_handler
52
+ @error_handler ||= lambda do |e|
53
+ logger.error "Queue#call::error => #{e.message}"
54
+ end
55
+ end
56
+
57
+ def error_handler=(func)
58
+ @error_handler = func
59
+ end
60
+
48
61
  extend self
49
62
 
50
63
  end
@@ -1,23 +1,23 @@
1
1
  module LambdaPunch
2
2
  class Logger
3
3
 
4
+ attr_reader :level
5
+
6
+ def initialize
7
+ @level = (ENV['LAMBDA_PUNCH_LOG_LEVEL'] || 'error').upcase.to_sym
8
+ end
9
+
4
10
  def logger
5
11
  @logger ||= ::Logger.new(STDOUT).tap do |l|
6
- l.level = level
12
+ l.level = logger_level
7
13
  l.formatter = proc { |_s, _d, _p, m| "[LambdaPunch] #{m}\n" }
8
14
  end
9
15
  end
10
16
 
11
- def level=(value)
12
- @level = value.to_s
13
- @logger = nil
14
- end
15
-
16
17
  private
17
18
 
18
- def level
19
- l = (@level || ENV['LAMBDA_PUNCH_LOG_LEVEL'] || 'fatal').upcase.to_sym
20
- ::Logger.const_defined?(l) ? ::Logger.const_get(l) : ::Logger::FATAL
19
+ def logger_level
20
+ ::Logger.const_defined?(@level) ? ::Logger.const_get(@level) : ::Logger::ERROR
21
21
  end
22
22
 
23
23
  end
@@ -18,8 +18,7 @@ module LambdaPunch
18
18
  begin
19
19
  job.call
20
20
  rescue => e
21
- logger.error "Queue#call::error => #{e.message}"
22
- # ...
21
+ LambdaPunch.error_handler.call(e)
23
22
  end
24
23
  end
25
24
  true
@@ -33,9 +32,5 @@ module LambdaPunch
33
32
  self.class.jobs
34
33
  end
35
34
 
36
- def logger
37
- LambdaPunch.logger
38
- end
39
-
40
35
  end
41
36
  end
@@ -0,0 +1,16 @@
1
+ module ActiveJob
2
+ module QueueAdapters
3
+ class LambdaPunchAdapter
4
+
5
+ def enqueue(job, options = {})
6
+ job_data = job.serialize
7
+ LambdaPunch.push { ActiveJob::Base.execute(job_data) }
8
+ end
9
+
10
+ def enqueue_at(job, timestamp)
11
+ enqueue(job)
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,7 @@
1
1
  require 'rails'
2
2
  require 'rails/engine'
3
-
3
+ require 'active_job'
4
+
4
5
  module LambdaPunch
5
6
  class Railtie < Rails::Railtie
6
7
  railtie_name :lambda_punch
@@ -1,3 +1,3 @@
1
1
  module LambdaPunch
2
- VERSION = "0.0.4"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -16,7 +16,7 @@ module LambdaPunch
16
16
  require 'timeout'
17
17
  require 'rb-inotify'
18
18
  DRb.start_service
19
- @queue = DRbObject.new_with_uri(Server.uri)
19
+ new_drb_queue
20
20
  end
21
21
 
22
22
  # Creates a new instance of this object with the event payload from the `LambdaPunch::Api#invoke`
@@ -26,6 +26,18 @@ module LambdaPunch
26
26
  new(event_payload).call
27
27
  end
28
28
 
29
+ # A safe and resilient way to call the remote queue.
30
+ #
31
+ def call_queue
32
+ queue.call
33
+ rescue DRb::DRbConnError
34
+ LambdaPunch.logger.error "Worker#call_queue => DRb::DRbConnError"
35
+ new_drb_queue
36
+ queue.call
37
+ end
38
+
39
+ private
40
+
29
41
  # The `@queue` object is the local process' reference to the application `LambdaPunch::Queue`
30
42
  # instance which does all the work in the applciation's scope.
31
43
  #
@@ -33,6 +45,10 @@ module LambdaPunch
33
45
  @queue
34
46
  end
35
47
 
48
+ def new_drb_queue
49
+ @queue = DRbObject.new_with_uri(Server.uri)
50
+ end
51
+
36
52
  end
37
53
 
38
54
  def initialize(event_payload)
@@ -48,22 +64,23 @@ module LambdaPunch
48
64
  # also ensures any clean up is done. For example, closing file notifications.
49
65
  #
50
66
  def call
51
- Timeout.timeout(timeout) { @notifier.process }
67
+ timeout { @notifier.process unless invoked? }
52
68
  rescue Timeout::Error
53
- logger.debug "Worker#call => Function timeout reached."
69
+ logger.error "Worker#call => Function timeout reached."
54
70
  ensure
55
71
  @notifier.close
56
- self.class.queue.call
72
+ self.class.call_queue
57
73
  end
58
74
 
59
75
  private
60
76
 
61
77
  # The Notifier's watch handler would set this instance variable to `true`. We also return `true`
62
78
  # if the extension's invoke palyload event has a `requestId` matching what the handler has written
63
- # to the `LambdaPunch::Notifier` file location. See also `request_ids_match?` method.
79
+ # to the `LambdaPunch::Notifier` file location. See also `request_ids_match?` method. Lastly if
80
+ # the timeout
64
81
  #
65
82
  def invoked?
66
- @invoked || request_ids_match?
83
+ @invoked || request_ids_match? || timed_out?
67
84
  end
68
85
 
69
86
  # The unique AWS reqeust id that both the extension and handler receive for each invoke. This one
@@ -86,13 +103,29 @@ module LambdaPunch
86
103
  request_id_payload == (request_id_notifier || Notifier.request_id)
87
104
  end
88
105
 
89
- # The function's timeout in seconds using the `INVOKE` event payload's `deadlineMs` value.
106
+ # A safe timeout method which accounts for a 0 or negative timeout value.
90
107
  #
91
108
  def timeout
109
+ @timeout = timeout_seconds
110
+ if timed_out?
111
+ yield
112
+ else
113
+ Timeout.timeout(@timeout) { yield }
114
+ end
115
+ end
116
+
117
+ # Helps guard for deadline milliseconds in the past.
118
+ #
119
+ def timed_out?
120
+ @timeout == 0 || @timeout < 0
121
+ end
122
+
123
+ # The function's timeout in seconds using the `INVOKE` event payload's `deadlineMs` value.
124
+ #
125
+ def timeout_seconds
92
126
  deadline_milliseconds = @event_payload['deadlineMs']
93
127
  deadline = Time.at(deadline_milliseconds / 1000.0)
94
- deadline_timeout = deadline - Time.now
95
- deadline_timeout > 0 ? deadline_timeout : 0
128
+ deadline - Time.now
96
129
  end
97
130
 
98
131
  # Our `LambdaPunch::Notifier` instance callback.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lambda_punch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-28 00:00:00.000000000 Z
11
+ date: 2021-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -66,6 +66,48 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-focus
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  description: 'LambdaPunch: Async Processing using Lambda Extensions'
70
112
  email:
71
113
  - ken@metaskills.net
@@ -99,6 +141,7 @@ files:
99
141
  - lib/lambda_punch/logger.rb
100
142
  - lib/lambda_punch/notifier.rb
101
143
  - lib/lambda_punch/queue.rb
144
+ - lib/lambda_punch/rails/active_job.rb
102
145
  - lib/lambda_punch/railtie.rb
103
146
  - lib/lambda_punch/server.rb
104
147
  - lib/lambda_punch/tasks/install.rake