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,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
|