lambda_punch 0.0.8 → 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: cec6cd5684a1a7ff22f75898d909f3189337f981d965c71d06cc53f447f2dda1
4
- data.tar.gz: 9825e8239cea26f6b2affe8b5387a1e12f377fa0ffb6a3371bbc6a7bcc5f3910
3
+ metadata.gz: eb70c0a40e9a90e863ea43325168469cfefb1a1c6825a9eced81de68314674c6
4
+ data.tar.gz: d31d67d900e3021aec70b88ce46fd119f11a1ee5e7b7f14f0c7fcee58a57a053
5
5
  SHA512:
6
- metadata.gz: ac0557df20c73e7ff75b082a14d63e8f96e57dc1bbd288a4670e11fb1f4d402688fa17a01f9215fee5db5798b371b73d9f6fe9dfe692b5c4e8bb6c59d9577240
7
- data.tar.gz: cea1aa8e78d416966a7d876e1035f12026e3b442cad4f95dd0935d145b012eef766a7c1a1a11332680fde1bf87af3e89023dae657130f487e00c849e2cf610f6
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,9 @@
1
+ ## [1.0.0] - 2021-07-05
2
+
3
+ ### Added
4
+
5
+ - Rails ActiveJob support.
6
+
1
7
  ## [0.0.8] - 2021-06-28
2
8
 
3
9
  - Guard against early notifier.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lambda_punch (0.0.8)
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,7 +84,7 @@ 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
 
@@ -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'] || 'error').upcase.to_sym
20
- ::Logger.const_defined?(l) ? ::Logger.const_get(l) : ::Logger::ERROR
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.8"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -64,7 +64,7 @@ module LambdaPunch
64
64
  # also ensures any clean up is done. For example, closing file notifications.
65
65
  #
66
66
  def call
67
- Timeout.timeout(timeout) { @notifier.process unless invoked? }
67
+ timeout { @notifier.process unless invoked? }
68
68
  rescue Timeout::Error
69
69
  logger.error "Worker#call => Function timeout reached."
70
70
  ensure
@@ -76,10 +76,11 @@ module LambdaPunch
76
76
 
77
77
  # The Notifier's watch handler would set this instance variable to `true`. We also return `true`
78
78
  # if the extension's invoke palyload event has a `requestId` matching what the handler has written
79
- # 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
80
81
  #
81
82
  def invoked?
82
- @invoked || request_ids_match?
83
+ @invoked || request_ids_match? || timed_out?
83
84
  end
84
85
 
85
86
  # The unique AWS reqeust id that both the extension and handler receive for each invoke. This one
@@ -102,13 +103,29 @@ module LambdaPunch
102
103
  request_id_payload == (request_id_notifier || Notifier.request_id)
103
104
  end
104
105
 
105
- # 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.
106
107
  #
107
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
108
126
  deadline_milliseconds = @event_payload['deadlineMs']
109
127
  deadline = Time.at(deadline_milliseconds / 1000.0)
110
- deadline_timeout = deadline - Time.now
111
- deadline_timeout > 0 ? deadline_timeout : 0
128
+ deadline - Time.now
112
129
  end
113
130
 
114
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.8
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-07-01 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