funktor 0.4.7 → 0.6.2
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 +4 -4
- data/.tool-versions +2 -0
- data/Gemfile.lock +31 -12
- data/funktor-testapp/.envrc +1 -0
- data/funktor-testapp/.gitignore +7 -0
- data/funktor-testapp/Gemfile +25 -0
- data/funktor-testapp/Gemfile.lock +51 -0
- data/funktor-testapp/app/services/job_flood.rb +38 -0
- data/funktor-testapp/app/workers/audit_worker.rb +49 -0
- data/funktor-testapp/app/workers/greetings_worker.rb +3 -0
- data/funktor-testapp/app/workers/hello_worker.rb +18 -0
- data/funktor-testapp/app/workers/single_thread_audit_worker.rb +3 -0
- data/funktor-testapp/deploy-dev.sh +5 -0
- data/funktor-testapp/funktor_config/boot.rb +17 -0
- data/funktor-testapp/funktor_config/environment.yml +15 -0
- data/funktor-testapp/funktor_config/function_definitions/default_queue_handler.yml +13 -0
- data/funktor-testapp/funktor_config/function_definitions/incoming_job_handler.yml +13 -0
- data/funktor-testapp/funktor_config/function_definitions/job_activator.yml +7 -0
- data/funktor-testapp/funktor_config/function_definitions/low_concurrency_queue_handler.yml +13 -0
- data/funktor-testapp/funktor_config/function_definitions/random_job_generator.yml +18 -0
- data/funktor-testapp/funktor_config/funktor.yml +114 -0
- data/funktor-testapp/funktor_config/iam_permissions/activity_table.yml +5 -0
- data/funktor-testapp/funktor_config/iam_permissions/default_queue.yml +8 -0
- data/funktor-testapp/funktor_config/iam_permissions/incoming_job_queue.yml +8 -0
- data/funktor-testapp/funktor_config/iam_permissions/jobs_table.yml +5 -0
- data/funktor-testapp/funktor_config/iam_permissions/jobs_table_secondary_index.yml +8 -0
- data/funktor-testapp/funktor_config/iam_permissions/low_concurrency_queue.yml +8 -0
- data/funktor-testapp/funktor_config/iam_permissions/ssm.yml +5 -0
- data/funktor-testapp/funktor_config/package.yml +11 -0
- data/funktor-testapp/funktor_config/resources/activity_table.yml +22 -0
- data/funktor-testapp/funktor_config/resources/cloudwatch_dashboard.yml +809 -0
- data/funktor-testapp/funktor_config/resources/default_queue.yml +22 -0
- data/funktor-testapp/funktor_config/resources/incoming_job_queue.yml +22 -0
- data/funktor-testapp/funktor_config/resources/incoming_job_queue_user.yml +26 -0
- data/funktor-testapp/funktor_config/resources/jobs_table.yml +56 -0
- data/funktor-testapp/funktor_config/resources/low_concurrency_queue.yml +22 -0
- data/funktor-testapp/funktor_config/ruby_layer.yml +11 -0
- data/funktor-testapp/funktor_init.yml +69 -0
- data/funktor-testapp/lambda_event_handlers/default_queue_handler.rb +8 -0
- data/funktor-testapp/lambda_event_handlers/incoming_job_handler.rb +8 -0
- data/funktor-testapp/lambda_event_handlers/job_activator.rb +8 -0
- data/funktor-testapp/lambda_event_handlers/low_concurrency_queue_handler.rb +8 -0
- data/funktor-testapp/lambda_event_handlers/random_job_generator.rb +35 -0
- data/funktor-testapp/package-lock.json +248 -0
- data/funktor-testapp/package.json +8 -0
- data/funktor-testapp/serverless.yml +66 -0
- data/funktor.gemspec +4 -1
- data/lib/active_job/queue_adapters/funktor_adapter.rb +3 -3
- data/lib/funktor/activity_tracker.rb +106 -0
- data/lib/funktor/cli/bootstrap.rb +0 -1
- data/lib/funktor/cli/init.rb +13 -0
- data/lib/funktor/cli/templates/app/workers/hello_worker.rb +1 -1
- data/lib/funktor/cli/templates/funktor_config/environment.yml +4 -0
- data/lib/funktor/cli/templates/funktor_config/function_definitions/incoming_job_handler.yml +3 -1
- data/lib/funktor/cli/templates/funktor_config/function_definitions/job_activator.yml +7 -0
- data/lib/funktor/cli/templates/funktor_config/function_definitions/work_queue_handler.yml +3 -1
- data/lib/funktor/cli/templates/funktor_config/funktor.yml +32 -6
- data/lib/funktor/cli/templates/funktor_config/iam_permissions/activity_table.yml +5 -0
- data/lib/funktor/cli/templates/funktor_config/iam_permissions/jobs_table.yml +5 -0
- data/lib/funktor/cli/templates/funktor_config/iam_permissions/jobs_table_secondary_index.yml +8 -0
- data/lib/funktor/cli/templates/funktor_config/resources/activity_table.yml +22 -0
- data/lib/funktor/cli/templates/funktor_config/resources/cloudwatch_dashboard.yml +13 -12
- data/lib/funktor/cli/templates/funktor_config/resources/incoming_job_queue.yml +2 -2
- data/lib/funktor/cli/templates/funktor_config/resources/jobs_table.yml +56 -0
- data/lib/funktor/cli/templates/funktor_config/resources/work_queue.yml +2 -2
- data/lib/funktor/cli/templates/funktor_init.yml.tt +16 -16
- data/lib/funktor/cli/templates/lambda_event_handlers/job_activator.rb +8 -0
- data/lib/funktor/cli/templates/lambda_event_handlers/work_queue_handler.rb +1 -1
- data/lib/funktor/cli/templates/serverless.yml +3 -2
- data/lib/funktor/counter.rb +4 -1
- data/lib/funktor/incoming_job_handler.rb +54 -18
- data/lib/funktor/job.rb +57 -7
- data/lib/funktor/job_activator.rb +124 -0
- data/lib/funktor/job_pusher.rb +0 -2
- data/lib/funktor/middleware/metrics.rb +8 -3
- data/lib/funktor/shard_utils.rb +6 -0
- data/lib/funktor/testing.rb +50 -47
- data/lib/funktor/version.rb +1 -1
- data/lib/funktor/web/application.rb +139 -0
- data/lib/funktor/web/views/index.erb +3 -0
- data/lib/funktor/web/views/layout.erb +58 -0
- data/lib/funktor/web/views/processing.erb +29 -0
- data/lib/funktor/web/views/queued.erb +29 -0
- data/lib/funktor/web/views/retries.erb +35 -0
- data/lib/funktor/web/views/scheduled.erb +26 -0
- data/lib/funktor/web/views/stats.erb +9 -0
- data/lib/funktor/web/views/table_stats_with_buttons.erb +11 -0
- data/lib/funktor/web.rb +1 -0
- data/lib/funktor/work_queue_handler.rb +101 -0
- data/lib/funktor/worker/funktor_options.rb +3 -1
- data/lib/funktor/worker.rb +8 -18
- data/lib/funktor.rb +52 -20
- metadata +109 -3
- data/lib/funktor/active_job_handler.rb +0 -58
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
require 'aws-sdk-dynamodb'
|
|
2
|
+
require 'aws-sdk-sqs'
|
|
3
|
+
|
|
4
|
+
module Funktor
|
|
5
|
+
class JobActivator
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@tracker = Funktor::ActivityTracker.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def dynamodb_client
|
|
12
|
+
@dynamodb_client ||= ::Aws::DynamoDB::Client.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def sqs_client
|
|
16
|
+
@sqs_client ||= ::Aws::SQS::Client.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def delayed_job_table
|
|
20
|
+
ENV['FUNKTOR_JOBS_TABLE']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def jobs_to_activate
|
|
24
|
+
# TODO : The lookahead time here should be configurable
|
|
25
|
+
# If this doesn't match the setting in the IncomingJobHandler some jobs
|
|
26
|
+
# might be activated and then immediately re-scheduled instead of being
|
|
27
|
+
# queued, which leads to kind of confusing stats for the "incoming" stat.
|
|
28
|
+
# (Come to think of it, the incoming stat is kind of confusting anyway since
|
|
29
|
+
# it reflects retries and scheduled jobs activations...)
|
|
30
|
+
target_time = (Time.now + 60).utc
|
|
31
|
+
query_params = {
|
|
32
|
+
expression_attribute_values: {
|
|
33
|
+
":queueable" => "true",
|
|
34
|
+
":targetTime" => target_time.iso8601
|
|
35
|
+
},
|
|
36
|
+
key_condition_expression: "queueable = :queueable AND performAt < :targetTime",
|
|
37
|
+
projection_expression: "jobId, jobShard, category",
|
|
38
|
+
table_name: delayed_job_table,
|
|
39
|
+
index_name: "performAtIndex"
|
|
40
|
+
}
|
|
41
|
+
resp = dynamodb_client.query(query_params)
|
|
42
|
+
return resp.items
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def queue_for_job(job)
|
|
46
|
+
queue_name = job.queue || 'default'
|
|
47
|
+
queue_constant = "FUNKTOR_#{queue_name.underscore.upcase}_QUEUE"
|
|
48
|
+
Funktor.logger.debug "queue_constant = #{queue_constant}"
|
|
49
|
+
Funktor.logger.debug "ENV value = #{ENV[queue_constant]}"
|
|
50
|
+
ENV[queue_constant] || ENV['FUNKTOR_DEFAULT_QUEUE']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def handle_item(item)
|
|
54
|
+
job_shard = item["jobShard"]
|
|
55
|
+
job_id = item["jobId"]
|
|
56
|
+
current_category = item["category"]
|
|
57
|
+
Funktor.logger.debug "jobShard = #{item['jobShard']}"
|
|
58
|
+
Funktor.logger.debug "jobId = #{item['jobId']}"
|
|
59
|
+
Funktor.logger.debug "current_category = #{current_category}"
|
|
60
|
+
activate_job(job_shard, job_id, current_category)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def activate_job(job_shard, job_id, current_category, queue_immediately = false)
|
|
64
|
+
# First we conditionally update the item in Dynamo to be sure that another scheduler hasn't gotten
|
|
65
|
+
# to it, and if that works then send to SQS. This is basically how Sidekiq scheduler works.
|
|
66
|
+
response = dynamodb_client.update_item({
|
|
67
|
+
key: {
|
|
68
|
+
"jobShard" => job_shard,
|
|
69
|
+
"jobId" => job_id
|
|
70
|
+
},
|
|
71
|
+
update_expression: "SET category = :category, queueable = :queueable",
|
|
72
|
+
condition_expression: "category = :current_category",
|
|
73
|
+
expression_attribute_values: {
|
|
74
|
+
":current_category" => current_category,
|
|
75
|
+
":queueable" => "false",
|
|
76
|
+
":category" => "queued"
|
|
77
|
+
},
|
|
78
|
+
table_name: delayed_job_table,
|
|
79
|
+
return_values: "ALL_OLD"
|
|
80
|
+
})
|
|
81
|
+
if response.attributes # this means the record was still there in the state we expected
|
|
82
|
+
Funktor.logger.debug "response.attributes ====== "
|
|
83
|
+
Funktor.logger.debug response.attributes
|
|
84
|
+
job = Funktor::Job.new(response.attributes["payload"])
|
|
85
|
+
Funktor.logger.debug "we created a job from payload"
|
|
86
|
+
Funktor.logger.debug response.attributes["payload"]
|
|
87
|
+
Funktor.logger.debug "queueing to #{job.retry_queue_url}"
|
|
88
|
+
if queue_immediately
|
|
89
|
+
job.delay = 0
|
|
90
|
+
end
|
|
91
|
+
sqs_client.send_message({
|
|
92
|
+
queue_url: job.retry_queue_url,
|
|
93
|
+
message_body: job.to_json
|
|
94
|
+
#delay_seconds: job.delay
|
|
95
|
+
})
|
|
96
|
+
if job.is_retry?
|
|
97
|
+
# We don't track here because we send stuff back to the incoming job queue and we track the
|
|
98
|
+
# :retryActivated even there.
|
|
99
|
+
# TODO - Once we're sure this is all working right we can delete the commented out line.
|
|
100
|
+
#@tracker.track(:retryActivated, job)
|
|
101
|
+
else
|
|
102
|
+
@tracker.track(:scheduledJobActivated, job)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
|
|
106
|
+
# This means that a different instance of the JobActivator (or someone doing stuff in the web UI)
|
|
107
|
+
# got to the job first.
|
|
108
|
+
Funktor.logger.debug "#{e.to_s} : #{e.message}"
|
|
109
|
+
Funktor.logger.debug e.backtrace.join("\n")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def call(event:, context:)
|
|
113
|
+
handled_item_count = 0
|
|
114
|
+
jobs_to_activate.each do |item|
|
|
115
|
+
if context.get_remaining_time_in_millis < 5_000 # This lets us exit gracefully and resume on the next round instead of getting forcibly killed.
|
|
116
|
+
puts "Bailing out due to milliseconds remaining #{context.get_remaining_time_in_millis}"
|
|
117
|
+
break
|
|
118
|
+
end
|
|
119
|
+
handle_item(item)
|
|
120
|
+
handled_item_count += 1
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
data/lib/funktor/job_pusher.rb
CHANGED
|
@@ -10,7 +10,12 @@ module Funktor
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def put_metric_to_stdout(time_diff, job)
|
|
13
|
-
|
|
13
|
+
# NOTE : We use raw_logger here instead of Funktor.loggert o avoid getting extra
|
|
14
|
+
# timestamps or log level information in the log line. We need this specific format to
|
|
15
|
+
# be the only thing in the line so that CloudWatch can parse the logs and use the data.
|
|
16
|
+
# 'unknown' is a log level that will always be logged, no matter what is set in the
|
|
17
|
+
# runtime environment as far as log level.
|
|
18
|
+
Funktor.raw_logger.unknown Funktor.dump_json(metric_hash(time_diff, job))
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
def metric_hash(time_diff_in_seconds, job)
|
|
@@ -43,8 +48,8 @@ module Funktor
|
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
|
-
Funktor.
|
|
47
|
-
config.
|
|
51
|
+
Funktor.configure_work_queue_handler do |config|
|
|
52
|
+
config.work_queue_handler_middleware do |chain|
|
|
48
53
|
chain.add Funktor::Middleware::Metrics
|
|
49
54
|
end
|
|
50
55
|
end
|
data/lib/funktor/testing.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
require 'funktor/worker'
|
|
2
|
+
require 'funktor/job_pusher'
|
|
2
3
|
require 'funktor/fake_job_queue'
|
|
3
4
|
|
|
4
5
|
module Funktor
|
|
6
|
+
|
|
5
7
|
module Worker
|
|
6
8
|
def self.clear_all
|
|
7
9
|
Funktor::FakeJobQueue.clear_all
|
|
@@ -25,67 +27,68 @@ module Funktor
|
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
30
|
+
|
|
28
31
|
class Testing
|
|
32
|
+
class << self
|
|
33
|
+
attr_accessor :mode
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def self.inline!(&block)
|
|
33
|
-
unless block_given?
|
|
34
|
-
raise "Funktor inline testing mode can only be called in block form."
|
|
35
|
+
def inline?
|
|
36
|
+
mode == :inline
|
|
35
37
|
end
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
end
|
|
38
|
+
|
|
39
|
+
def fake?
|
|
40
|
+
mode == :fake
|
|
40
41
|
end
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
|
|
43
|
+
def inline!(&block)
|
|
44
|
+
unless block_given?
|
|
45
|
+
raise "Funktor inline testing mode can only be called in block form."
|
|
45
46
|
end
|
|
47
|
+
set_mode(:inline, &block)
|
|
46
48
|
end
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
chain.add Funktor::FakeJobPusherMiddleware
|
|
49
|
+
|
|
50
|
+
def fake!(&block)
|
|
51
|
+
set_mode(:fake, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def disable!
|
|
55
|
+
set_mode(:disabled)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def set_mode(new_mode, &block)
|
|
59
|
+
if block_given?
|
|
60
|
+
original_mode = mode
|
|
61
|
+
self.mode = new_mode
|
|
62
|
+
begin
|
|
63
|
+
yield
|
|
64
|
+
ensure
|
|
65
|
+
self.mode = original_mode
|
|
65
66
|
end
|
|
67
|
+
else
|
|
68
|
+
self.mode = new_mode
|
|
66
69
|
end
|
|
67
70
|
end
|
|
68
71
|
end
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module TestingPusher
|
|
75
|
+
def push(payload)
|
|
76
|
+
if Funktor::Testing.inline?
|
|
77
|
+
Funktor.job_pusher_middleware.invoke(payload) do
|
|
78
|
+
payload = payload.with_indifferent_access
|
|
79
|
+
worker = Object.const_get payload["worker"]
|
|
80
|
+
worker.new.perform(*payload["worker_params"])
|
|
73
81
|
end
|
|
82
|
+
elsif Funktor::Testing.fake?
|
|
83
|
+
Funktor.job_pusher_middleware.invoke(payload) do
|
|
84
|
+
Funktor::FakeJobQueue.push(payload)
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
super
|
|
74
88
|
end
|
|
75
89
|
end
|
|
76
90
|
end
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
def call(payload)
|
|
80
|
-
payload = payload.with_indifferent_access
|
|
81
|
-
worker = Object.const_get payload["worker"]
|
|
82
|
-
worker.new.perform(*payload["worker_params"])
|
|
83
|
-
end
|
|
84
|
-
end
|
|
92
|
+
Funktor::JobPusher.prepend TestingPusher
|
|
85
93
|
|
|
86
|
-
class FakeJobPusherMiddleware
|
|
87
|
-
def call(payload)
|
|
88
|
-
Funktor::FakeJobQueue.push(payload)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
94
|
end
|
data/lib/funktor/version.rb
CHANGED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require 'sinatra/base'
|
|
2
|
+
require 'aws-sdk-dynamodb'
|
|
3
|
+
require_relative '../../funktor'
|
|
4
|
+
require_relative '../../funktor/shard_utils'
|
|
5
|
+
require_relative '../../funktor/activity_tracker'
|
|
6
|
+
|
|
7
|
+
module Funktor
|
|
8
|
+
module Web
|
|
9
|
+
class Application < Sinatra::Base
|
|
10
|
+
include ShardUtils
|
|
11
|
+
|
|
12
|
+
get '/' do
|
|
13
|
+
erb :index, layout: :layout, locals: {
|
|
14
|
+
activity_data: get_activity_data
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
get '/scheduled' do
|
|
19
|
+
erb :scheduled, layout: :layout, locals: {
|
|
20
|
+
activity_data: get_activity_data,
|
|
21
|
+
jobs: get_jobs('scheduled')
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
get '/retries' do
|
|
26
|
+
erb :retries, layout: :layout, locals: {
|
|
27
|
+
activity_data: get_activity_data,
|
|
28
|
+
jobs: get_jobs('retry')
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
get '/queued' do
|
|
33
|
+
erb :queued, layout: :layout, locals: {
|
|
34
|
+
activity_data: get_activity_data,
|
|
35
|
+
jobs: get_jobs('queued')
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
get '/processing' do
|
|
40
|
+
erb :processing, layout: :layout, locals: {
|
|
41
|
+
activity_data: get_activity_data,
|
|
42
|
+
jobs: get_jobs('processing')
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
post '/update_jobs' do
|
|
47
|
+
job_ids = params[:job_id]
|
|
48
|
+
if job_ids.is_a?(String)
|
|
49
|
+
job_ids = [job_ids]
|
|
50
|
+
end
|
|
51
|
+
job_ids ||= []
|
|
52
|
+
puts "params[:submit] = #{params[:submit]}"
|
|
53
|
+
puts "job_ids = #{job_ids}"
|
|
54
|
+
puts "params[:source] = #{params[:source]}"
|
|
55
|
+
if params[:submit] == "Delete Selected Jobs"
|
|
56
|
+
delete_jobs(job_ids, params[:source])
|
|
57
|
+
elsif params[:submit] == "Queue Selected Jobs"
|
|
58
|
+
queue_jobs(job_ids, params[:source])
|
|
59
|
+
end
|
|
60
|
+
redirect request.referrer
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def get_jobs(category)
|
|
64
|
+
"Jobs of type #{category}"
|
|
65
|
+
query_params = {
|
|
66
|
+
expression_attribute_values: {
|
|
67
|
+
":category" => category
|
|
68
|
+
},
|
|
69
|
+
key_condition_expression: "category = :category",
|
|
70
|
+
projection_expression: "payload, performAt, jobId, jobShard",
|
|
71
|
+
table_name: ENV['FUNKTOR_JOBS_TABLE'],
|
|
72
|
+
index_name: "categoryIndex"
|
|
73
|
+
}
|
|
74
|
+
resp = dynamodb_client.query(query_params)
|
|
75
|
+
@items = resp.items
|
|
76
|
+
@jobs = @items.map{ |item| Funktor::Job.new(item["payload"]) }
|
|
77
|
+
return @jobs
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def get_activity_data
|
|
81
|
+
query_params = {
|
|
82
|
+
expression_attribute_values: {
|
|
83
|
+
":category" => "stat"
|
|
84
|
+
},
|
|
85
|
+
key_condition_expression: "category = :category",
|
|
86
|
+
projection_expression: "statName, stat_value",
|
|
87
|
+
table_name: ENV['FUNKTOR_ACTIVITY_TABLE']
|
|
88
|
+
}
|
|
89
|
+
resp = dynamodb_client.query(query_params)
|
|
90
|
+
@activity_stats = {}
|
|
91
|
+
resp.items.each do |item|
|
|
92
|
+
@activity_stats[item["statName"]] = item["stat_value"].to_i
|
|
93
|
+
end
|
|
94
|
+
return @activity_stats
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def queue_jobs(job_ids, source)
|
|
98
|
+
job_activator = Funktor::JobActivator.new
|
|
99
|
+
job_ids.each do |job_id|
|
|
100
|
+
job_shard = calculate_shard(job_id)
|
|
101
|
+
job_activator.activate_job(job_shard, job_id, source, true)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def delete_jobs(job_ids, source)
|
|
106
|
+
@tracker = Funktor::ActivityTracker.new
|
|
107
|
+
job_ids.each do |job_id|
|
|
108
|
+
delete_single_job(job_id, source)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def delete_single_job(job_id, source)
|
|
113
|
+
response = dynamodb_client.delete_item({
|
|
114
|
+
key: {
|
|
115
|
+
"jobShard" => calculate_shard(job_id),
|
|
116
|
+
"jobId" => job_id
|
|
117
|
+
},
|
|
118
|
+
table_name: ENV['FUNKTOR_JOBS_TABLE'],
|
|
119
|
+
return_values: "ALL_OLD"
|
|
120
|
+
})
|
|
121
|
+
if response.attributes # this means the record was still there
|
|
122
|
+
if source == "scheduled"
|
|
123
|
+
@tracker.track(:scheduledJobDeleted, nil)
|
|
124
|
+
elsif source == "retry"
|
|
125
|
+
@tracker.track(:retryDeleted, nil)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def dynamodb_client
|
|
131
|
+
@dynamodb_client ||= ::Aws::DynamoDB::Client.new
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# start the server if ruby file executed directly
|
|
135
|
+
run! if app_file == $0
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
|
4
|
+
<style type="text/css" media="screen">
|
|
5
|
+
/* Green Light scheme (Default) */
|
|
6
|
+
/* Can be forced with data-theme="light" */
|
|
7
|
+
[data-theme="light"],
|
|
8
|
+
:root:not([data-theme="dark"]) {
|
|
9
|
+
--primary: #43a047;
|
|
10
|
+
--primary-hover: #388e3c;
|
|
11
|
+
--primary-focus: rgba(67, 160, 71, 0.125);
|
|
12
|
+
--primary-inverse: #FFF;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Green Dark scheme (Auto) */
|
|
16
|
+
/* Automatically enabled if user has Dark mode enabled */
|
|
17
|
+
@media only screen and (prefers-color-scheme: dark) {
|
|
18
|
+
:root:not([data-theme="light"]) {
|
|
19
|
+
--primary: #43a047;
|
|
20
|
+
--primary-hover: #4caf50;
|
|
21
|
+
--primary-focus: rgba(67, 160, 71, 0.25);
|
|
22
|
+
--primary-inverse: #FFF;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Green Dark scheme (Forced) */
|
|
27
|
+
/* Enabled if forced with data-theme="dark" */
|
|
28
|
+
[data-theme="dark"] {
|
|
29
|
+
--primary: #43a047;
|
|
30
|
+
--primary-hover: #4caf50;
|
|
31
|
+
--primary-focus: rgba(67, 160, 71, 0.25);
|
|
32
|
+
--primary-inverse: #FFF;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Green (Common styles) */
|
|
36
|
+
:root {
|
|
37
|
+
--form-element-active-border-color: var(--primary);
|
|
38
|
+
--form-element-focus-color: var(--primary-focus);
|
|
39
|
+
--switch-color: var(--primary-inverse);
|
|
40
|
+
--switch-checked-background-color: var(--primary);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* custom stuff for the funktor dashboard */
|
|
44
|
+
table.header h5{
|
|
45
|
+
margin-bottom: 0;
|
|
46
|
+
}
|
|
47
|
+
body > main{
|
|
48
|
+
padding: 0;
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
51
|
+
</head>
|
|
52
|
+
<body>
|
|
53
|
+
<%= erb :stats %>
|
|
54
|
+
<main class="container-fluid">
|
|
55
|
+
<%= yield %>
|
|
56
|
+
</main>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|