funktor 0.2.1
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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +154 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/funktor +13 -0
- data/exe/funktor-deploy +8 -0
- data/funktor.gemspec +38 -0
- data/lib/funktor.rb +63 -0
- data/lib/funktor/active_job_handler.rb +52 -0
- data/lib/funktor/aws/sqs/event.rb +20 -0
- data/lib/funktor/aws/sqs/record.rb +14 -0
- data/lib/funktor/cli/application.rb +23 -0
- data/lib/funktor/cli/bootstrap.rb +35 -0
- data/lib/funktor/cli/generate.rb +0 -0
- data/lib/funktor/cli/generate/base.rb +13 -0
- data/lib/funktor/cli/generate/work_queue.rb +25 -0
- data/lib/funktor/cli/init.rb +78 -0
- data/lib/funktor/cli/templates/Gemfile +9 -0
- data/lib/funktor/cli/templates/config/environment.yml +4 -0
- data/lib/funktor/cli/templates/config/funktor.yml +51 -0
- data/lib/funktor/cli/templates/config/package.yml +9 -0
- data/lib/funktor/cli/templates/config/ruby_layer.yml +11 -0
- data/lib/funktor/cli/templates/function_definitions/active_job_handler.yml +11 -0
- data/lib/funktor/cli/templates/function_definitions/incoming_job_handler.yml +11 -0
- data/lib/funktor/cli/templates/funktor.yml.tt +51 -0
- data/lib/funktor/cli/templates/gitignore +2 -0
- data/lib/funktor/cli/templates/handlers/active_job_handler.rb +17 -0
- data/lib/funktor/cli/templates/handlers/incoming_job_handler.rb +8 -0
- data/lib/funktor/cli/templates/iam_permissions/active_job_queue.yml +8 -0
- data/lib/funktor/cli/templates/iam_permissions/incoming_job_queue.yml +8 -0
- data/lib/funktor/cli/templates/iam_permissions/ssm.yml +5 -0
- data/lib/funktor/cli/templates/package.json +1 -0
- data/lib/funktor/cli/templates/resources/active_job_queue.yml +22 -0
- data/lib/funktor/cli/templates/resources/cloudwatch_dashboard.yml +518 -0
- data/lib/funktor/cli/templates/resources/incoming_job_queue.yml +22 -0
- data/lib/funktor/cli/templates/resources/incoming_job_queue_user.yml +26 -0
- data/lib/funktor/cli/templates/serverless.yml +54 -0
- data/lib/funktor/cli/templates/workers/hello_worker.rb +8 -0
- data/lib/funktor/deploy/cli.rb +42 -0
- data/lib/funktor/deploy/serverless.rb +60 -0
- data/lib/funktor/deploy/serverless_templates/serverless.yml +156 -0
- data/lib/funktor/fake_job_queue.rb +15 -0
- data/lib/funktor/incoming_job_handler.rb +39 -0
- data/lib/funktor/job.rb +76 -0
- data/lib/funktor/middleware/metrics.rb +51 -0
- data/lib/funktor/middleware_chain.rb +62 -0
- data/lib/funktor/testing.rb +69 -0
- data/lib/funktor/version.rb +3 -0
- data/lib/funktor/worker.rb +86 -0
- metadata +173 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
module Funktor
|
2
|
+
module Middleware
|
3
|
+
class Metrics
|
4
|
+
def call(job)
|
5
|
+
start_time = Time.now.utc
|
6
|
+
yield
|
7
|
+
end_time = Time.now.utc
|
8
|
+
time_diff = end_time - start_time
|
9
|
+
put_metric_to_stdout(time_diff, job)
|
10
|
+
end
|
11
|
+
|
12
|
+
def put_metric_to_stdout(time_diff, job)
|
13
|
+
puts Funktor.dump_json(metric_hash(time_diff, job))
|
14
|
+
end
|
15
|
+
|
16
|
+
def metric_hash(time_diff_in_seconds, job)
|
17
|
+
{
|
18
|
+
"_aws": {
|
19
|
+
"Timestamp": Time.now.strftime('%s%3N').to_i,
|
20
|
+
"CloudWatchMetrics": [
|
21
|
+
{
|
22
|
+
"Namespace": "rails-lambda-experiment", # TODO - We should get this from config or someting
|
23
|
+
"Dimensions": [["WorkerClassName"]],
|
24
|
+
"Metrics": [ # CPU, Memory, Duration, etc...
|
25
|
+
{
|
26
|
+
"Name": "Duration",
|
27
|
+
"Unit": "Milliseconds"
|
28
|
+
}
|
29
|
+
]
|
30
|
+
}
|
31
|
+
]
|
32
|
+
},
|
33
|
+
"WorkerClassName": job.worker_class_name,
|
34
|
+
"Duration": time_diff_in_seconds * 1_000
|
35
|
+
#"count": value,
|
36
|
+
#"requestId": "989ffbf8-9ace-4817-a57c-e4dd734019ee"
|
37
|
+
}
|
38
|
+
#data[key] = value
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Funktor.configure_active_job_handler do |config|
|
46
|
+
config.active_job_handler_middleware do |chain|
|
47
|
+
chain.add Funktor::Middleware::Metrics
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Funktor
|
2
|
+
class MiddlewareChain
|
3
|
+
attr_reader :entries
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@entries = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def remove(klass)
|
10
|
+
entries.delete_if { |entry| entry.klass == klass }
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(klass, *args)
|
14
|
+
remove(klass)
|
15
|
+
entries << Entry.new(klass, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def prepend(klass, *args)
|
19
|
+
remove(klass)
|
20
|
+
entries.insert(0, Entry.new(klass, *args))
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert_before(oldklass, newklass, *args)
|
24
|
+
remove(newklass)
|
25
|
+
i = entries.index { |entry| entry.klass == oldklass } || 0
|
26
|
+
entries.insert(i, Entry.new(newklass, *args))
|
27
|
+
end
|
28
|
+
|
29
|
+
def insert_after(oldklass, newklass, *args)
|
30
|
+
remove(newklass)
|
31
|
+
i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
|
32
|
+
entries.insert(i + 1, Entry.new(newklass, *args))
|
33
|
+
end
|
34
|
+
|
35
|
+
def invoke(*args)
|
36
|
+
return yield if @entries.empty?
|
37
|
+
|
38
|
+
middlewares = entries.map(&:instantiate)
|
39
|
+
traverse_chain = proc do
|
40
|
+
if middlewares.empty?
|
41
|
+
yield
|
42
|
+
else
|
43
|
+
middlewares.shift.call(*args, &traverse_chain)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
traverse_chain.call
|
47
|
+
end
|
48
|
+
|
49
|
+
class Entry
|
50
|
+
attr_reader :klass
|
51
|
+
|
52
|
+
def initialize(klass, *args)
|
53
|
+
@klass = klass
|
54
|
+
@args = args
|
55
|
+
end
|
56
|
+
|
57
|
+
def instantiate
|
58
|
+
@klass.new(*@args)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'funktor/worker'
|
2
|
+
require 'funktor/fake_job_queue'
|
3
|
+
|
4
|
+
module Funktor
|
5
|
+
module Worker
|
6
|
+
def self.clear_all
|
7
|
+
Funktor::FakeJobQueue.clear_all
|
8
|
+
end
|
9
|
+
module ClassMethods
|
10
|
+
def jobs
|
11
|
+
Funktor::FakeJobQueue.jobs[self.name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
15
|
+
jobs.clear
|
16
|
+
end
|
17
|
+
|
18
|
+
def work_all_jobs
|
19
|
+
while jobs.any?
|
20
|
+
job_data = jobs.shift
|
21
|
+
worker = job_data[:worker]
|
22
|
+
worker_params = job_data[:payload][:worker_params]
|
23
|
+
worker.new.perform(worker_params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
class Testing
|
29
|
+
|
30
|
+
def self.inline!(&block)
|
31
|
+
Funktor.configure_job_pusher do |config|
|
32
|
+
config.job_pusher_middleware do |chain|
|
33
|
+
chain.add Funktor::InlineJobPusherMiddleware
|
34
|
+
end
|
35
|
+
end
|
36
|
+
yield
|
37
|
+
Funktor.configure_job_pusher do |config|
|
38
|
+
config.job_pusher_middleware do |chain|
|
39
|
+
chain.remove Funktor::InlineJobPusherMiddleware
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def self.fake!(&block)
|
44
|
+
Funktor.configure_job_pusher do |config|
|
45
|
+
config.job_pusher_middleware do |chain|
|
46
|
+
chain.add Funktor::FakeJobPusherMiddleware
|
47
|
+
end
|
48
|
+
end
|
49
|
+
yield
|
50
|
+
Funktor.configure_job_pusher do |config|
|
51
|
+
config.job_pusher_middleware do |chain|
|
52
|
+
chain.remove Funktor::FakeJobPusherMiddleware
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class InlineJobPusherMiddleware
|
59
|
+
def call(worker, payload)
|
60
|
+
worker.new.perform(payload[:worker_params])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class FakeJobPusherMiddleware
|
65
|
+
def call(worker, payload)
|
66
|
+
Funktor::FakeJobQueue.push(worker, payload)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'aws-sdk-sqs'
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module Funktor
|
6
|
+
class DelayTooLongError < StandardError; end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Funktor::Worker
|
10
|
+
def self.included(base)
|
11
|
+
base.extend ClassMethods
|
12
|
+
base.class_eval do
|
13
|
+
cattr_accessor :funktor_options_hash
|
14
|
+
#alias_method :perform_later, :perform_async
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def funktor_options(options = {})
|
20
|
+
self.funktor_options_hash = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_funktor_options
|
24
|
+
self.funktor_options_hash || {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def custom_queue_url
|
28
|
+
get_funktor_options[:queue_url]
|
29
|
+
end
|
30
|
+
|
31
|
+
def queue_url
|
32
|
+
# TODO : Should this default to FUNKTOR_ACTIVE_JOB_QUEUE?
|
33
|
+
# Depends how e handle this in pro...?
|
34
|
+
custom_queue_url || ENV['FUNKTOR_INCOMING_JOB_QUEUE']
|
35
|
+
end
|
36
|
+
|
37
|
+
def perform_async(*worker_params)
|
38
|
+
self.perform_in(0, *worker_params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def perform_at(time, *worker_params)
|
42
|
+
delay = (time.utc - Time.now.utc).round
|
43
|
+
if delay < 0
|
44
|
+
delay = 0
|
45
|
+
end
|
46
|
+
self.perform_in(delay, *worker_params)
|
47
|
+
end
|
48
|
+
|
49
|
+
def perform_in(delay, *worker_params)
|
50
|
+
if delay > max_delay
|
51
|
+
raise Funktor::DelayTooLongError.new("The delay can't be longer than #{max_delay} seconds. This is a limitation of SQS. Funktor Pro has mechanisms to work around this limitation.")
|
52
|
+
end
|
53
|
+
self.push_to_incoming_job_queue(delay, *worker_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
def push_to_incoming_job_queue(delay, *worker_params)
|
57
|
+
job_id = SecureRandom.uuid
|
58
|
+
payload = build_job_payload(job_id, delay, *worker_params)
|
59
|
+
|
60
|
+
Funktor.job_pusher_middleware.invoke(self, payload) do
|
61
|
+
client.send_message({
|
62
|
+
queue_url: queue_url,
|
63
|
+
message_body: Funktor.dump_json(payload)
|
64
|
+
})
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def max_delay
|
69
|
+
900
|
70
|
+
end
|
71
|
+
|
72
|
+
def client
|
73
|
+
@client ||= Aws::SQS::Client.new
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_job_payload(job_id, delay, *worker_params)
|
77
|
+
{
|
78
|
+
worker: self.name,
|
79
|
+
worker_params: worker_params,
|
80
|
+
job_id: job_id,
|
81
|
+
delay: delay,
|
82
|
+
funktor_options: get_funktor_options
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: funktor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeremy Green
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-sqs
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.37'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.37'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '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'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
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
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webmock
|
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
|
+
description: Background processing in AWS Lambda.
|
84
|
+
email:
|
85
|
+
- jeremy@octolabs.com
|
86
|
+
executables:
|
87
|
+
- funktor
|
88
|
+
- funktor-deploy
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rspec"
|
94
|
+
- ".travis.yml"
|
95
|
+
- CODE_OF_CONDUCT.md
|
96
|
+
- Gemfile
|
97
|
+
- Gemfile.lock
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- bin/console
|
102
|
+
- bin/setup
|
103
|
+
- exe/funktor
|
104
|
+
- exe/funktor-deploy
|
105
|
+
- funktor.gemspec
|
106
|
+
- lib/funktor.rb
|
107
|
+
- lib/funktor/active_job_handler.rb
|
108
|
+
- lib/funktor/aws/sqs/event.rb
|
109
|
+
- lib/funktor/aws/sqs/record.rb
|
110
|
+
- lib/funktor/cli/application.rb
|
111
|
+
- lib/funktor/cli/bootstrap.rb
|
112
|
+
- lib/funktor/cli/generate.rb
|
113
|
+
- lib/funktor/cli/generate/base.rb
|
114
|
+
- lib/funktor/cli/generate/work_queue.rb
|
115
|
+
- lib/funktor/cli/init.rb
|
116
|
+
- lib/funktor/cli/templates/Gemfile
|
117
|
+
- lib/funktor/cli/templates/config/environment.yml
|
118
|
+
- lib/funktor/cli/templates/config/funktor.yml
|
119
|
+
- lib/funktor/cli/templates/config/package.yml
|
120
|
+
- lib/funktor/cli/templates/config/ruby_layer.yml
|
121
|
+
- lib/funktor/cli/templates/function_definitions/active_job_handler.yml
|
122
|
+
- lib/funktor/cli/templates/function_definitions/incoming_job_handler.yml
|
123
|
+
- lib/funktor/cli/templates/funktor.yml.tt
|
124
|
+
- lib/funktor/cli/templates/gitignore
|
125
|
+
- lib/funktor/cli/templates/handlers/active_job_handler.rb
|
126
|
+
- lib/funktor/cli/templates/handlers/incoming_job_handler.rb
|
127
|
+
- lib/funktor/cli/templates/iam_permissions/active_job_queue.yml
|
128
|
+
- lib/funktor/cli/templates/iam_permissions/incoming_job_queue.yml
|
129
|
+
- lib/funktor/cli/templates/iam_permissions/ssm.yml
|
130
|
+
- lib/funktor/cli/templates/package.json
|
131
|
+
- lib/funktor/cli/templates/resources/active_job_queue.yml
|
132
|
+
- lib/funktor/cli/templates/resources/cloudwatch_dashboard.yml
|
133
|
+
- lib/funktor/cli/templates/resources/incoming_job_queue.yml
|
134
|
+
- lib/funktor/cli/templates/resources/incoming_job_queue_user.yml
|
135
|
+
- lib/funktor/cli/templates/serverless.yml
|
136
|
+
- lib/funktor/cli/templates/workers/hello_worker.rb
|
137
|
+
- lib/funktor/deploy/cli.rb
|
138
|
+
- lib/funktor/deploy/serverless.rb
|
139
|
+
- lib/funktor/deploy/serverless_templates/serverless.yml
|
140
|
+
- lib/funktor/fake_job_queue.rb
|
141
|
+
- lib/funktor/incoming_job_handler.rb
|
142
|
+
- lib/funktor/job.rb
|
143
|
+
- lib/funktor/middleware/metrics.rb
|
144
|
+
- lib/funktor/middleware_chain.rb
|
145
|
+
- lib/funktor/testing.rb
|
146
|
+
- lib/funktor/version.rb
|
147
|
+
- lib/funktor/worker.rb
|
148
|
+
homepage: https://github.com/Octo-Labs/funktor
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata:
|
152
|
+
homepage_uri: https://github.com/Octo-Labs/funktor
|
153
|
+
source_code_uri: https://github.com/Octo-Labs/funktor
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options: []
|
156
|
+
require_paths:
|
157
|
+
- lib
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: 2.3.0
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubygems_version: 3.1.4
|
170
|
+
signing_key:
|
171
|
+
specification_version: 4
|
172
|
+
summary: Background processing in AWS Lambda.
|
173
|
+
test_files: []
|