funktor 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,22 @@
|
|
1
|
+
Resources:
|
2
|
+
IncomingJobQueue:
|
3
|
+
Type: AWS::SQS::Queue
|
4
|
+
Properties:
|
5
|
+
QueueName: ${self:custom.funktor.incomingJobQueueName}
|
6
|
+
VisibilityTimeout: 300
|
7
|
+
RedrivePolicy:
|
8
|
+
deadLetterTargetArn:
|
9
|
+
"Fn::GetAtt": [ IncomingJobDeadLetterQueue, Arn ]
|
10
|
+
maxReceiveCount: 5
|
11
|
+
IncomingJobDeadLetterQueue:
|
12
|
+
Type: AWS::SQS::Queue
|
13
|
+
Properties:
|
14
|
+
QueueName: ${self:custom.funktor.incomingDeadJobQueueName}
|
15
|
+
|
16
|
+
Outputs:
|
17
|
+
IncomingJobQueueUrl:
|
18
|
+
Value:
|
19
|
+
Ref: IncomingJobQueue
|
20
|
+
IncomingJobDeadLetterQueueUrl:
|
21
|
+
Value:
|
22
|
+
Ref: IncomingJobDeadLetterQueue
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Resources:
|
2
|
+
IncomingJobQueueUser:
|
3
|
+
Type: AWS::IAM::User
|
4
|
+
Properties:
|
5
|
+
Policies:
|
6
|
+
- PolicyName: incoming-job-queue-access
|
7
|
+
PolicyDocument:
|
8
|
+
Version: '2012-10-17'
|
9
|
+
Statement:
|
10
|
+
- Effect: Allow
|
11
|
+
Action:
|
12
|
+
- sqs:*
|
13
|
+
Resource:
|
14
|
+
- "Fn::GetAtt": [ IncomingJobQueue, Arn ]
|
15
|
+
|
16
|
+
IncomingJobQueueUserAccessKey:
|
17
|
+
Type: AWS::IAM::AccessKey
|
18
|
+
Properties:
|
19
|
+
UserName: !Ref IncomingJobQueueUser
|
20
|
+
|
21
|
+
|
22
|
+
Outputs:
|
23
|
+
AccessKeyID:
|
24
|
+
Value: !Ref IncomingJobQueueUserAccessKey
|
25
|
+
SecretAccessKey:
|
26
|
+
Value: !GetAtt IncomingJobQueueUserAccessKey.SecretAccessKey
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Welcome to Funktor & Serverless!
|
2
|
+
#
|
3
|
+
# This file is the main config file for your service.
|
4
|
+
# It's already configured to run Funktor, you just have to deploy it.
|
5
|
+
#
|
6
|
+
# For more info about Funktor:
|
7
|
+
# TODO
|
8
|
+
#
|
9
|
+
# For more about serverless, check their docs:
|
10
|
+
# docs.serverless.com
|
11
|
+
#
|
12
|
+
# Happy Coding!
|
13
|
+
|
14
|
+
# The name of your service. All your AWS resources will contain this name.
|
15
|
+
service: yourapp-funktor
|
16
|
+
|
17
|
+
# This causes serverless to throw an error early if the config is bad, instead of waiting for CloudFormation to try and fail to deploy it.
|
18
|
+
configValidationMode: error
|
19
|
+
|
20
|
+
# Pin the serverless framework to the 2.x line
|
21
|
+
frameworkVersion: '2'
|
22
|
+
|
23
|
+
provider:
|
24
|
+
name: aws
|
25
|
+
runtime: ruby2.7
|
26
|
+
lambdaHashingVersion: 20201221
|
27
|
+
environment: ${file(config/environment.yml)}
|
28
|
+
iamRoleStatements:
|
29
|
+
- ${file(iam_permissions/ssm.yml)}
|
30
|
+
- ${file(iam_permissions/active_job_queue.yml)}
|
31
|
+
- ${file(iam_permissions/incoming_job_queue.yml)}
|
32
|
+
|
33
|
+
|
34
|
+
custom:
|
35
|
+
# Our stage is based on what is passed in when running serverless
|
36
|
+
# commands. Or fallsback to what we have set in the provider section.
|
37
|
+
stage: ${self:provider.stage, 'dev'}
|
38
|
+
funktor: ${file(config/funktor.yml)}
|
39
|
+
rubyLayer: ${file(config/ruby_layer.yml)}
|
40
|
+
|
41
|
+
package: ${file(config/package.yml)}
|
42
|
+
|
43
|
+
functions:
|
44
|
+
incomingJobHandler: ${file(function_definitions/incoming_job_handler.yml)}
|
45
|
+
activeJobHandler: ${file(function_definitions/active_job_handler.yml)}
|
46
|
+
|
47
|
+
resources:
|
48
|
+
- ${file(resources/active_job_queue.yml)}
|
49
|
+
- ${file(resources/incoming_job_queue.yml)}
|
50
|
+
- ${file(resources/incoming_job_queue_user.yml)}
|
51
|
+
- ${file(resources/cloudwatch_dashboard.yml)}
|
52
|
+
|
53
|
+
plugins:
|
54
|
+
- /Users/jgreen/projects/serverless-ruby-layer
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'funktor/deploy/serverless'
|
3
|
+
|
4
|
+
module Funktor
|
5
|
+
module Deploy
|
6
|
+
class CLI
|
7
|
+
attr_reader :options
|
8
|
+
def initialize
|
9
|
+
@options = {
|
10
|
+
verbose: false,
|
11
|
+
file: 'funktor.yml',
|
12
|
+
tmp_dir_prefix: '.funktor',
|
13
|
+
stage: 'dev'
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse(argv = ARGV)
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.on('-v', '--verbose', 'Display verbose output') do |verbose|
|
20
|
+
options[:verbose] = verbose
|
21
|
+
end
|
22
|
+
opts.on('-f', '--file=FILE', 'The path to the funktor.yml file to deploy') do |file|
|
23
|
+
options[:file] = file
|
24
|
+
end
|
25
|
+
opts.on('-t', '--tmp_dir_prefix=TMP_DIR_PREFIX', 'The prefix for the tmp dir. The stage will be appended.') do |tmp_dir_prefix|
|
26
|
+
options[:tmp_dir_prefix] = tmp_dir_prefix
|
27
|
+
end
|
28
|
+
opts.on('-s', '--stage=STAGE', 'The stage to deploy to. Defaults to "dev"') do |stage|
|
29
|
+
options[:stage] = stage
|
30
|
+
end
|
31
|
+
opts.on('-h') { puts opts; exit }
|
32
|
+
opts.parse!(argv)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run
|
37
|
+
Funktor::Deploy::Serverless.new(**options).call
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Funktor
|
4
|
+
module Deploy
|
5
|
+
class Serverless
|
6
|
+
attr_accessor :file, :tmp_dir_prefix, :verbose, :stage
|
7
|
+
def initialize(file:, tmp_dir_prefix:, verbose:, stage:)
|
8
|
+
@file = file
|
9
|
+
@tmp_dir_prefix = tmp_dir_prefix
|
10
|
+
@verbose = verbose
|
11
|
+
@stage = stage
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
#puts "deploying file #{file} via tmp_dir_prefix #{tmp_dir_prefix} for stage #{stage}"
|
16
|
+
make_tmp_dir
|
17
|
+
create_serverless_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def funktor_data
|
21
|
+
@funktor_data ||= squash_hash(YAML.load_file(file))
|
22
|
+
end
|
23
|
+
|
24
|
+
def squash_hash(hsh, stack=[])
|
25
|
+
hsh.reduce({}) do |res, (key, val)|
|
26
|
+
next_stack = [ *stack, key ]
|
27
|
+
if val.is_a?(Hash)
|
28
|
+
next res.merge(squash_hash(val, next_stack))
|
29
|
+
end
|
30
|
+
res.merge(next_stack.join(".").to_sym => val)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def make_tmp_dir
|
35
|
+
FileUtils.mkdir_p tmp_dir
|
36
|
+
end
|
37
|
+
|
38
|
+
def tmp_dir
|
39
|
+
"#{tmp_dir_prefix}_#{stage}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_serverless_file
|
43
|
+
#puts "funktor_data = "
|
44
|
+
#puts funktor_data
|
45
|
+
template_source = File.open(serverless_file_source).read
|
46
|
+
file_content = template_source % funktor_data
|
47
|
+
File.open(serverless_file_destination, 'w') { |file| file.write(file_content) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def serverless_file_source
|
51
|
+
File.expand_path("../serverless_templates/serverless.yml", __FILE__)
|
52
|
+
end
|
53
|
+
|
54
|
+
def serverless_file_destination
|
55
|
+
File.join tmp_dir, 'serverless.yml'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# WARNING : You probably don't want to mess with this file directly.
|
2
|
+
service: %{stack_name}
|
3
|
+
# app and org for use with dashboard.serverless.com
|
4
|
+
#app: your-app-name
|
5
|
+
#org: your-org-name
|
6
|
+
|
7
|
+
frameworkVersion: '2'
|
8
|
+
|
9
|
+
provider:
|
10
|
+
name: aws
|
11
|
+
runtime: %{runtime}
|
12
|
+
lambdaHashingVersion: 20201221
|
13
|
+
ecr:
|
14
|
+
images:
|
15
|
+
funktorimage:
|
16
|
+
path: ./
|
17
|
+
# TODO : Expose buildArgs via funktor.yml?
|
18
|
+
buildArgs:
|
19
|
+
BUNDLE_GEM__FURY__IO: ${env:BUNDLE_GEM__FURY__IO}
|
20
|
+
# TODO : Expose environment to funktor.yml?
|
21
|
+
environment:
|
22
|
+
FUNKTOR_INCOMING_JOB_QUEUE:
|
23
|
+
Ref: IncomingJobQueue
|
24
|
+
FUNKTOR_ACTIVE_JOB_QUEUE:
|
25
|
+
Ref: ActiveJobQueue
|
26
|
+
FUNKTOR_DELAYED_JOB_TABLE:
|
27
|
+
Ref: DelayedJobTable
|
28
|
+
delayedJobTable:
|
29
|
+
Ref: DelayedJobTable
|
30
|
+
iamRoleStatements:
|
31
|
+
- Effect: Allow
|
32
|
+
Action:
|
33
|
+
- ssm:Get*
|
34
|
+
Resource:
|
35
|
+
- '*' # TODO : This should probably be more selective...
|
36
|
+
- Effect: Allow
|
37
|
+
Action:
|
38
|
+
- sqs:ReceiveMessage
|
39
|
+
- sqs:DeleteMessage
|
40
|
+
- sqs:SendMessage
|
41
|
+
- sqs:GetQueueAttributes
|
42
|
+
Resource:
|
43
|
+
- "Fn::GetAtt": [ ActiveJobQueue, Arn ]
|
44
|
+
- Effect: Allow
|
45
|
+
Action:
|
46
|
+
- sqs:ReceiveMessage
|
47
|
+
- sqs:DeleteMessage
|
48
|
+
- sqs:SendMessage
|
49
|
+
- sqs:GetQueueAttributes
|
50
|
+
Resource:
|
51
|
+
- "Fn::GetAtt": [ IncomingJobQueue, Arn ]
|
52
|
+
- Effect: Allow
|
53
|
+
Action:
|
54
|
+
- sqs:ReceiveMessage
|
55
|
+
- sqs:DeleteMessage
|
56
|
+
- sqs:SendMessage
|
57
|
+
- sqs:GetQueueAttributes
|
58
|
+
Resource:
|
59
|
+
- "Fn::GetAtt": [ ActivityQueue, Arn ]
|
60
|
+
- Effect: Allow
|
61
|
+
Action:
|
62
|
+
- dynamodb:PutItem
|
63
|
+
- dynamodb:DeleteItem
|
64
|
+
Resource:
|
65
|
+
- "Fn::GetAtt": [ DelayedJobTable, Arn ]
|
66
|
+
- Effect: Allow
|
67
|
+
Action:
|
68
|
+
- dynamodb:*
|
69
|
+
Resource:
|
70
|
+
- "Fn::GetAtt": [ StatsTable, Arn ]
|
71
|
+
- Effect: Allow
|
72
|
+
Action:
|
73
|
+
- dynamodb:Query
|
74
|
+
Resource:
|
75
|
+
Fn::Join:
|
76
|
+
- ""
|
77
|
+
- - "Fn::GetAtt": [ DelayedJobTable, Arn ]
|
78
|
+
- "/index/performAtIndex"
|
79
|
+
|
80
|
+
custom:
|
81
|
+
# Our stage is based on what is passed in when running serverless
|
82
|
+
# commands. Or fallsback to what we have set in the provider section.
|
83
|
+
stage: ${opt:stage, 'dev'}
|
84
|
+
incomingJobQueueName: ${self:service}-${self:custom.stage}-incoming-jobs
|
85
|
+
incomingJobQueueAccessPolicyName: ${self:service}-${self:custom.stage}-incoming-job-queue-access
|
86
|
+
incomingDeadJobQueueName: ${self:service}-${self:custom.stage}-incoming-dead-jobs
|
87
|
+
activeJobQueueName: ${self:service}-${self:custom.stage}-active-jobs
|
88
|
+
activityQueueName: ${self:service}-${self:custom.stage}-activity
|
89
|
+
activityDeadQueueName: ${self:service}-${self:custom.stage}-activity-dead
|
90
|
+
deadJobQueueName: ${self:service}-${self:custom.stage}-dead-jobs
|
91
|
+
delayedJobTableName: ${self:service}-${self:custom.stage}-delayed-jobs
|
92
|
+
statsTableName: ${self:service}-${self:custom.stage}-stats
|
93
|
+
dashboardName: ${self:service}-${self:custom.stage}-dashboard
|
94
|
+
|
95
|
+
# you can define service wide environment variables here
|
96
|
+
# environment:
|
97
|
+
# variable1: value1
|
98
|
+
|
99
|
+
functions:
|
100
|
+
# TODO - How could other functions be passed in from funktor.yml?
|
101
|
+
#random_job_generator:
|
102
|
+
##handler: lambda_handlers/random_job_generator.RandomJobGenerator.call
|
103
|
+
#image:
|
104
|
+
#name: funktorimage
|
105
|
+
#command:
|
106
|
+
#- lambda_handlers/random_job_generator.RandomJobGenerator.call
|
107
|
+
#timeout: 170
|
108
|
+
#reservedConcurrency: 0
|
109
|
+
#events:
|
110
|
+
#- schedule: rate(1 minute)
|
111
|
+
|
112
|
+
delayed_job_activator:
|
113
|
+
image:
|
114
|
+
name: funktorimage
|
115
|
+
command:
|
116
|
+
- lambda_handlers/delayed_job_activator.call
|
117
|
+
timeout: %{delayed_job_activator.timeout_in_seconds}
|
118
|
+
# TODO - handle memory and concurrency
|
119
|
+
#reservedConcurrency: 1
|
120
|
+
events:
|
121
|
+
- schedule: %{delayed_job_activator.execution_schedule}
|
122
|
+
|
123
|
+
incoming_job_handler:
|
124
|
+
image:
|
125
|
+
name: funktorimage
|
126
|
+
command:
|
127
|
+
- lambda_handlers/incoming_job_handler.call
|
128
|
+
timeout: %{incoming_job_handler.timeout_in_seconds}
|
129
|
+
events:
|
130
|
+
- sqs:
|
131
|
+
arn:
|
132
|
+
Fn::GetAtt:
|
133
|
+
- IncomingJobQueue
|
134
|
+
- Arn
|
135
|
+
|
136
|
+
# TODO - We need one of these per work queue
|
137
|
+
active_job_handler:
|
138
|
+
image:
|
139
|
+
name: funktorimage
|
140
|
+
command:
|
141
|
+
- lambda_handlers/active_job_handler.call
|
142
|
+
timeout: 300
|
143
|
+
events:
|
144
|
+
- sqs:
|
145
|
+
arn:
|
146
|
+
Fn::GetAtt:
|
147
|
+
- ActiveJobQueue
|
148
|
+
- Arn
|
149
|
+
|
150
|
+
# you can add CloudFormation resource templates here
|
151
|
+
resources:
|
152
|
+
- ${file(resources/sqs-queue.yml)}
|
153
|
+
- ${file(resources/sqs-incoming-user.yml)}
|
154
|
+
- ${file(resources/dynamodb-table.yml)}
|
155
|
+
- ${file(resources/cloudfront-dashboard.yml)}
|
156
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Funktor
|
2
|
+
module FakeJobQueue
|
3
|
+
def self.push(worker, payload)
|
4
|
+
jobs[worker.name].push({worker: worker, payload: payload})
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.jobs
|
8
|
+
@jobs ||= Hash.new { |hash, key| hash[key] = [] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.clear_all
|
12
|
+
jobs.clear
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'aws-sdk-sqs'
|
2
|
+
|
3
|
+
module Funktor
|
4
|
+
class IncomingJobHandler
|
5
|
+
|
6
|
+
def call(event:, context:)
|
7
|
+
event = Funktor::Aws::Sqs::Event.new(event)
|
8
|
+
puts "event.jobs.count = #{event.jobs.count}"
|
9
|
+
event.jobs.each do |job|
|
10
|
+
dispatch(job)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sqs_client
|
15
|
+
@sqs_client ||= ::Aws::SQS::Client.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def dispatch(job)
|
19
|
+
Funktor.incoming_job_handler_middleware.invoke(job) do
|
20
|
+
puts "pushing to active_job_queue for delay = #{job.delay}"
|
21
|
+
push_to_active_job_queue(job)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def active_job_queue
|
26
|
+
ENV['FUNKTOR_ACTIVE_JOB_QUEUE']
|
27
|
+
end
|
28
|
+
|
29
|
+
def push_to_active_job_queue(job)
|
30
|
+
sqs_client.send_message({
|
31
|
+
# TODO : How to get this URL...
|
32
|
+
queue_url: active_job_queue,
|
33
|
+
message_body: job.to_json,
|
34
|
+
delay_seconds: job.delay
|
35
|
+
})
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/lib/funktor/job.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module Funktor
|
2
|
+
class Job
|
3
|
+
attr_accessor :job_string
|
4
|
+
attr_accessor :job_data
|
5
|
+
def initialize(job_string)
|
6
|
+
@job_string = job_string
|
7
|
+
end
|
8
|
+
|
9
|
+
def job_data
|
10
|
+
@job_data ||= Funktor.parse_json(job_string)
|
11
|
+
end
|
12
|
+
|
13
|
+
def worker_class_name
|
14
|
+
job_data["worker"]
|
15
|
+
end
|
16
|
+
|
17
|
+
def job_id
|
18
|
+
job_data["job_id"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def worker_params
|
22
|
+
job_data["worker_params"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def retries
|
26
|
+
job_data["retries"] || 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def retries=(retries)
|
30
|
+
job_data["retries"] = retries
|
31
|
+
end
|
32
|
+
|
33
|
+
def delay
|
34
|
+
job_data["delay"]
|
35
|
+
end
|
36
|
+
|
37
|
+
def delay=(delay)
|
38
|
+
job_data["delay"] = delay
|
39
|
+
end
|
40
|
+
|
41
|
+
def execute
|
42
|
+
worker_class.new.perform(worker_params)
|
43
|
+
end
|
44
|
+
|
45
|
+
def worker_class
|
46
|
+
@klass ||= Object.const_get worker_class_name
|
47
|
+
end
|
48
|
+
|
49
|
+
def increment_retries
|
50
|
+
self.retries ||= 0
|
51
|
+
self.retries += 1
|
52
|
+
self.delay = seconds_to_delay(retries)
|
53
|
+
end
|
54
|
+
|
55
|
+
# delayed_job and sidekiq use the same basic formula
|
56
|
+
def seconds_to_delay(count)
|
57
|
+
(count**4) + 15 + (rand(30) * (count + 1))
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_json(arg = nil)
|
61
|
+
Funktor.dump_json(job_data)
|
62
|
+
end
|
63
|
+
|
64
|
+
def retry_limit
|
65
|
+
25
|
66
|
+
end
|
67
|
+
|
68
|
+
def can_retry
|
69
|
+
self.retries < retry_limit
|
70
|
+
end
|
71
|
+
|
72
|
+
def retry_queue_url
|
73
|
+
worker_class&.custom_queue_url || ENV['FUNKTOR_INCOMING_JOB_QUEUE']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|