funktor 0.4.7 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +2 -0
  3. data/Gemfile.lock +31 -12
  4. data/funktor-testapp/.envrc +1 -0
  5. data/funktor-testapp/.gitignore +7 -0
  6. data/funktor-testapp/Gemfile +25 -0
  7. data/funktor-testapp/Gemfile.lock +51 -0
  8. data/funktor-testapp/app/services/job_flood.rb +38 -0
  9. data/funktor-testapp/app/workers/audit_worker.rb +49 -0
  10. data/funktor-testapp/app/workers/greetings_worker.rb +3 -0
  11. data/funktor-testapp/app/workers/hello_worker.rb +18 -0
  12. data/funktor-testapp/app/workers/single_thread_audit_worker.rb +3 -0
  13. data/funktor-testapp/deploy-dev.sh +5 -0
  14. data/funktor-testapp/funktor_config/boot.rb +17 -0
  15. data/funktor-testapp/funktor_config/environment.yml +15 -0
  16. data/funktor-testapp/funktor_config/function_definitions/default_queue_handler.yml +13 -0
  17. data/funktor-testapp/funktor_config/function_definitions/incoming_job_handler.yml +13 -0
  18. data/funktor-testapp/funktor_config/function_definitions/job_activator.yml +7 -0
  19. data/funktor-testapp/funktor_config/function_definitions/low_concurrency_queue_handler.yml +13 -0
  20. data/funktor-testapp/funktor_config/function_definitions/random_job_generator.yml +18 -0
  21. data/funktor-testapp/funktor_config/funktor.yml +114 -0
  22. data/funktor-testapp/funktor_config/iam_permissions/activity_table.yml +5 -0
  23. data/funktor-testapp/funktor_config/iam_permissions/default_queue.yml +8 -0
  24. data/funktor-testapp/funktor_config/iam_permissions/incoming_job_queue.yml +8 -0
  25. data/funktor-testapp/funktor_config/iam_permissions/jobs_table.yml +5 -0
  26. data/funktor-testapp/funktor_config/iam_permissions/jobs_table_secondary_index.yml +8 -0
  27. data/funktor-testapp/funktor_config/iam_permissions/low_concurrency_queue.yml +8 -0
  28. data/funktor-testapp/funktor_config/iam_permissions/ssm.yml +5 -0
  29. data/funktor-testapp/funktor_config/package.yml +11 -0
  30. data/funktor-testapp/funktor_config/resources/activity_table.yml +22 -0
  31. data/funktor-testapp/funktor_config/resources/cloudwatch_dashboard.yml +809 -0
  32. data/funktor-testapp/funktor_config/resources/default_queue.yml +22 -0
  33. data/funktor-testapp/funktor_config/resources/incoming_job_queue.yml +22 -0
  34. data/funktor-testapp/funktor_config/resources/incoming_job_queue_user.yml +26 -0
  35. data/funktor-testapp/funktor_config/resources/jobs_table.yml +56 -0
  36. data/funktor-testapp/funktor_config/resources/low_concurrency_queue.yml +22 -0
  37. data/funktor-testapp/funktor_config/ruby_layer.yml +11 -0
  38. data/funktor-testapp/funktor_init.yml +69 -0
  39. data/funktor-testapp/lambda_event_handlers/default_queue_handler.rb +8 -0
  40. data/funktor-testapp/lambda_event_handlers/incoming_job_handler.rb +8 -0
  41. data/funktor-testapp/lambda_event_handlers/job_activator.rb +8 -0
  42. data/funktor-testapp/lambda_event_handlers/low_concurrency_queue_handler.rb +8 -0
  43. data/funktor-testapp/lambda_event_handlers/random_job_generator.rb +35 -0
  44. data/funktor-testapp/package-lock.json +248 -0
  45. data/funktor-testapp/package.json +8 -0
  46. data/funktor-testapp/serverless.yml +66 -0
  47. data/funktor.gemspec +4 -1
  48. data/lib/active_job/queue_adapters/funktor_adapter.rb +3 -3
  49. data/lib/funktor/activity_tracker.rb +106 -0
  50. data/lib/funktor/cli/bootstrap.rb +0 -1
  51. data/lib/funktor/cli/init.rb +13 -0
  52. data/lib/funktor/cli/templates/app/workers/hello_worker.rb +1 -1
  53. data/lib/funktor/cli/templates/funktor_config/environment.yml +4 -0
  54. data/lib/funktor/cli/templates/funktor_config/function_definitions/incoming_job_handler.yml +3 -1
  55. data/lib/funktor/cli/templates/funktor_config/function_definitions/job_activator.yml +7 -0
  56. data/lib/funktor/cli/templates/funktor_config/function_definitions/work_queue_handler.yml +3 -1
  57. data/lib/funktor/cli/templates/funktor_config/funktor.yml +32 -6
  58. data/lib/funktor/cli/templates/funktor_config/iam_permissions/activity_table.yml +5 -0
  59. data/lib/funktor/cli/templates/funktor_config/iam_permissions/jobs_table.yml +5 -0
  60. data/lib/funktor/cli/templates/funktor_config/iam_permissions/jobs_table_secondary_index.yml +8 -0
  61. data/lib/funktor/cli/templates/funktor_config/resources/activity_table.yml +22 -0
  62. data/lib/funktor/cli/templates/funktor_config/resources/cloudwatch_dashboard.yml +13 -12
  63. data/lib/funktor/cli/templates/funktor_config/resources/incoming_job_queue.yml +2 -2
  64. data/lib/funktor/cli/templates/funktor_config/resources/jobs_table.yml +56 -0
  65. data/lib/funktor/cli/templates/funktor_config/resources/work_queue.yml +2 -2
  66. data/lib/funktor/cli/templates/funktor_init.yml.tt +16 -16
  67. data/lib/funktor/cli/templates/lambda_event_handlers/job_activator.rb +8 -0
  68. data/lib/funktor/cli/templates/lambda_event_handlers/work_queue_handler.rb +1 -1
  69. data/lib/funktor/cli/templates/serverless.yml +3 -2
  70. data/lib/funktor/counter.rb +4 -1
  71. data/lib/funktor/incoming_job_handler.rb +54 -18
  72. data/lib/funktor/job.rb +57 -7
  73. data/lib/funktor/job_activator.rb +124 -0
  74. data/lib/funktor/job_pusher.rb +0 -2
  75. data/lib/funktor/middleware/metrics.rb +8 -3
  76. data/lib/funktor/shard_utils.rb +6 -0
  77. data/lib/funktor/testing.rb +50 -47
  78. data/lib/funktor/version.rb +1 -1
  79. data/lib/funktor/web/application.rb +139 -0
  80. data/lib/funktor/web/views/index.erb +3 -0
  81. data/lib/funktor/web/views/layout.erb +58 -0
  82. data/lib/funktor/web/views/processing.erb +29 -0
  83. data/lib/funktor/web/views/queued.erb +29 -0
  84. data/lib/funktor/web/views/retries.erb +35 -0
  85. data/lib/funktor/web/views/scheduled.erb +26 -0
  86. data/lib/funktor/web/views/stats.erb +9 -0
  87. data/lib/funktor/web/views/table_stats_with_buttons.erb +11 -0
  88. data/lib/funktor/web.rb +1 -0
  89. data/lib/funktor/work_queue_handler.rb +101 -0
  90. data/lib/funktor/worker/funktor_options.rb +3 -1
  91. data/lib/funktor/worker.rb +8 -18
  92. data/lib/funktor.rb +52 -20
  93. metadata +109 -3
  94. data/lib/funktor/active_job_handler.rb +0 -58
@@ -0,0 +1,114 @@
1
+ IncomingJobHandler:
2
+ # timeout is how long the handler can possibly run. Up to 10 messages may be delivered
3
+ # to a handler at one time, so you'll want this to be at least 10x the maximum time you
4
+ # expect to spend for one message. The incoming job handler usually will be pretty fast,
5
+ # but we default to a high number here to allow for the times when things go weird.
6
+ functionTimeout: 300
7
+ # reservedConcurrency represents the maximum number of concurrent executions.
8
+ # For the incoming job handler you probably don't want to limit it because you
9
+ # want to get things onto work queues as quickly as possible.
10
+ reservedConcurrency: null
11
+ # provisionedConcurrency represents the number of lambda functions that will always
12
+ # be available. For the incoming jobs handler you probably don't need to set this
13
+ # unless your jobs are very bursty AND very time sensitive.
14
+ provisionedConcurrency: null
15
+ # Use memory_size to adjust the reousrces (both memory and CPU) available.
16
+ # For the incoming jobs handler you probably don't need this to be too large,
17
+ # but if you're seeing large delays at this stage it might help to bump it up.
18
+ memorySize: 256
19
+ batchSize: 1
20
+ maximumBatchingWindow: 0
21
+ visibilityTimeout: 1800
22
+ maxReceiveCount: 20
23
+
24
+ JobActivator:
25
+ # timeout is how long the handler can possibly run. Up to 10 messages may be delivered
26
+ # to a handler at one time, so you'll want this to be at least 10x the maximum time you
27
+ # expect to spend for one message. The job activator usually will be pretty fast,
28
+ # but we default to a high number here to allow for the times when things go weird.
29
+ functionTimeout: 300
30
+ # reservedConcurrency represents the maximum number of concurrent executions.
31
+ # For the job activator you probably don't want to limit it because you
32
+ # want to get things onto work queues as quickly as possible when they're ready.
33
+ reservedConcurrency: null
34
+ # provisionedConcurrency represents the number of lambda functions that will always
35
+ # be available. For the job activator you probably don't need to set this
36
+ # since it will be running on a schedule
37
+ provisionedConcurrency: null
38
+ # Use memory_size to adjust the reousrces (both memory and CPU) available.
39
+ # For the job activator you probably don't need this to be too large,
40
+ # but if you're seeing large delays at this stage it might help to bump it up.
41
+ memorySize: 256
42
+ batchSize: 1
43
+ maximumBatchingWindow: 0
44
+ visibilityTimeout: 1800
45
+ maxReceiveCount: 20
46
+
47
+
48
+
49
+ DefaultQueueHandler:
50
+ # timeout is how long the handler can possibly run. Up to 10 messages may be delivered
51
+ # to a handler at one time, so you'll want this to be at least 10x the maximum time you
52
+ # expect to spend for one message. The active job handler may be slow if your jobs are
53
+ # doing a lot of work, so we default to the maximum here.
54
+ functionTimeout: 300
55
+ # reservedConcurrency represents the maximum number of concurrent executions.
56
+ # For the active job handler you may want to limit it if you have resource limitations
57
+ # like database connections that you need to avoid exhausting.
58
+ reservedConcurrency: null
59
+ # provisionedConcurrency represents the number of lambda functions that will always
60
+ # be available. For the active job handler you probably don't need to set this
61
+ # unless your jobs are very bursty AND very time sensitive.
62
+ provisionedConcurrency: null
63
+ # Use memory_size to adjust the reousrces (both memory and CPU) available.
64
+ # For the active jobs handler you'll want this to be at least as large as the memory
65
+ # required to actually do your jobs. You can choose an even higher number to increase
66
+ # the available CPU to make the jobs run faster.
67
+ memorySize: 256
68
+ batchSize: 1
69
+ maximumBatchingWindow: 0
70
+ visibilityTimeout: 1800
71
+ maxReceiveCount: 20
72
+
73
+ LowConcurrencyQueueHandler:
74
+ # timeout is how long the handler can possibly run. Up to 10 messages may be delivered
75
+ # to a handler at one time, so you'll want this to be at least 10x the maximum time you
76
+ # expect to spend for one message. The active job handler may be slow if your jobs are
77
+ # doing a lot of work, so we default to the maximum here.
78
+ functionTimeout: 300
79
+ # reservedConcurrency represents the maximum number of concurrent executions.
80
+ # For the active job handler you may want to limit it if you have resource limitations
81
+ # like database connections that you need to avoid exhausting.
82
+ reservedConcurrency: 10
83
+ # provisionedConcurrency represents the number of lambda functions that will always
84
+ # be available. For the active job handler you probably don't need to set this
85
+ # unless your jobs are very bursty AND very time sensitive.
86
+ provisionedConcurrency: null
87
+ # Use memory_size to adjust the reousrces (both memory and CPU) available.
88
+ # For the active jobs handler you'll want this to be at least as large as the memory
89
+ # required to actually do your jobs. You can choose an even higher number to increase
90
+ # the available CPU to make the jobs run faster.
91
+ memorySize: 256
92
+ batchSize: 1
93
+ maximumBatchingWindow: 0
94
+ visibilityTimeout: 1800
95
+ maxReceiveCount: 20
96
+
97
+
98
+
99
+ # You shouldn't need to mess with these under most circumstances. But you could if you want to change
100
+ # the name of some of your resources in AWS.
101
+ IncomingJobQueueName: ${self:service}-${self:custom.stage}-incoming-jobs
102
+ IncomingDeadJobQueueName: ${self:service}-${self:custom.stage}-incoming-dead
103
+ IncomingJobHandlerName: ${self:service}-${self:custom.stage}-IncomingJobHandler
104
+ IncomingJobQueueAccessPolicyName: ${self:service}-${self:custom.stage}-incoming-job-queue-access
105
+ DashboardName: ${self:service}-${self:custom.stage}-dashboard
106
+ DefaultQueueName: ${self:service}-${self:custom.stage}-default
107
+ DefaultDeadJobQueueName: ${self:service}-${self:custom.stage}-default-dead
108
+ DefaultQueueHandlerName: ${self:service}-${self:custom.stage}-DefaultQueueHandler
109
+ LowConcurrencyQueueName: ${self:service}-${self:custom.stage}-low-concurrency
110
+ LowConcurrencyDeadJobQueueName: ${self:service}-${self:custom.stage}-low-concurrency-dead
111
+ LowConcurrencyQueueHandlerName: ${self:service}-${self:custom.stage}-LowConcurrencyQueueHandler
112
+ JobsTableName: ${self:service}-${self:custom.stage}-jobs
113
+ ActivityTableName: ${self:service}-${self:custom.stage}-activity
114
+ JobActivatorName: ${self:service}-${self:custom.stage}-JobActivator
@@ -0,0 +1,5 @@
1
+ Effect: Allow
2
+ Action:
3
+ - dynamodb:*
4
+ Resource:
5
+ - "Fn::GetAtt": [ ActivityTable, Arn ]
@@ -0,0 +1,8 @@
1
+ Effect: Allow
2
+ Action:
3
+ - sqs:ReceiveMessage
4
+ - sqs:DeleteMessage
5
+ - sqs:SendMessage
6
+ - sqs:GetQueueAttributes
7
+ Resource:
8
+ - "Fn::GetAtt": [ DefaultQueue, Arn ]
@@ -0,0 +1,8 @@
1
+ Effect: Allow
2
+ Action:
3
+ - sqs:ReceiveMessage
4
+ - sqs:DeleteMessage
5
+ - sqs:SendMessage
6
+ - sqs:GetQueueAttributes
7
+ Resource:
8
+ - "Fn::GetAtt": [ IncomingJobQueue, Arn ]
@@ -0,0 +1,5 @@
1
+ Effect: Allow
2
+ Action:
3
+ - dynamodb:*
4
+ Resource:
5
+ - "Fn::GetAtt": [ JobsTable, Arn ]
@@ -0,0 +1,8 @@
1
+ Effect: Allow
2
+ Action:
3
+ - dynamodb:Query
4
+ Resource:
5
+ Fn::Join:
6
+ - ""
7
+ - - "Fn::GetAtt": [ JobsTable, Arn ]
8
+ - "/index/performAtIndex"
@@ -0,0 +1,8 @@
1
+ Effect: Allow
2
+ Action:
3
+ - sqs:ReceiveMessage
4
+ - sqs:DeleteMessage
5
+ - sqs:SendMessage
6
+ - sqs:GetQueueAttributes
7
+ Resource:
8
+ - "Fn::GetAtt": [ LowConcurrencyQueue, Arn ]
@@ -0,0 +1,5 @@
1
+ Effect: Allow
2
+ Action:
3
+ - ssm:Get*
4
+ Resource:
5
+ - '*' # TODO : This should probably be more selective...
@@ -0,0 +1,11 @@
1
+ # TODO - Figure out how to allow individual packaging to work out of the box.
2
+ individually: false
3
+ include:
4
+ - Gemfile
5
+ - Gemfile.lock
6
+ - funktor_config/boot.rb
7
+ - app/**
8
+ # Evertyting is excluded by default with serverless-ruby-layer, but you could use
9
+ # the lines below to exlude files that are inside an include path.
10
+ #exclude:
11
+ # - workers/excluded_worker.rb
@@ -0,0 +1,22 @@
1
+ Resources:
2
+ ActivityTable:
3
+ Type: AWS::DynamoDB::Table
4
+ Properties:
5
+ # Generate a name based on the stage
6
+ TableName: ${self:custom.funktor.ActivityTableName}
7
+ BillingMode: PAY_PER_REQUEST
8
+ AttributeDefinitions:
9
+ - AttributeName: category
10
+ AttributeType: S
11
+ - AttributeName: statName
12
+ AttributeType: S
13
+ KeySchema:
14
+ - AttributeName: category
15
+ KeyType: HASH
16
+ - AttributeName: statName
17
+ KeyType: RANGE
18
+
19
+ Outputs:
20
+ ActivityTable:
21
+ Value:
22
+ Ref: ActivityTable
@@ -0,0 +1,809 @@
1
+ Resources:
2
+ FunktorDashboard:
3
+ Type: AWS::CloudWatch::Dashboard
4
+ Properties:
5
+ DashboardName: ${self:custom.funktor.DashboardName}
6
+ DashboardBody: >
7
+ {
8
+ "widgets": [
9
+
10
+
11
+
12
+ {
13
+ "height": 3,
14
+ "width": 24,
15
+ "y": 0,
16
+ "x": 0,
17
+ "type": "text",
18
+ "properties": {
19
+ "markdown": "\n# Funktor Auto-generated Dashbaord\n\n This dashboard is auto-generated by Funktor and will be updated as Funktor progresses. If you want to customize this dashboard you should use 'Actions => Save dashbaord as' in the toolbar above to create a new dashboard of your own.\n\n The upper section shows you high level queue and worker stats, the lower sections show more details about all the AWS resources at play."
20
+ }
21
+ },
22
+
23
+
24
+ {
25
+ "height": 6,
26
+ "width": 12,
27
+ "y": 3,
28
+ "x": 12,
29
+ "type": "metric",
30
+ "properties": {
31
+ "metrics": [
32
+ [ "funktor-testapp", "Duration", "WorkerClassName", "AuditWorker" ],
33
+ [ "...", { "stat": "p99" } ],
34
+ [ "funktor-testapp", "Duration", "WorkerClassName", "GreetingsWorker" ],
35
+ [ "...", { "stat": "p99" } ],
36
+ [ "funktor-testapp", "Duration", "WorkerClassName", "HelloWorker" ],
37
+ [ "...", { "stat": "p99" } ],
38
+ [ "funktor-testapp", "Duration", "WorkerClassName", "SingleThreadAuditWorker" ],
39
+ [ "...", { "stat": "p99" } ]
40
+ ],
41
+ "view": "timeSeries",
42
+ "stacked": false,
43
+ "region": "us-east-1",
44
+ "stat": "Average",
45
+ "period": 60,
46
+ "title": "Job Duration by Worker"
47
+ }
48
+ },
49
+
50
+ {
51
+ "height": 6,
52
+ "width": 12,
53
+ "y": 3,
54
+ "x": 0,
55
+ "type": "metric",
56
+ "properties": {
57
+ "metrics": [
58
+ [ "funktor-testapp", "processed", "WorkerClassName", "AuditWorker" ],
59
+ [ ".", "failed", ".", "." ],
60
+ [ "funktor-testapp", "processed", "WorkerClassName", "GreetingsWorker" ],
61
+ [ ".", "failed", ".", "." ],
62
+ [ "funktor-testapp", "processed", "WorkerClassName", "HelloWorker" ],
63
+ [ ".", "failed", ".", "." ],
64
+ [ "funktor-testapp", "processed", "WorkerClassName", "SingleThreadAuditWorker" ],
65
+ [ ".", "failed", ".", "." ]
66
+ ],
67
+ "view": "timeSeries",
68
+ "stacked": false,
69
+ "region": "us-east-1",
70
+ "title": "Process/Failed Jobs By Worker",
71
+ "period": 60,
72
+ "stat": "Sum"
73
+ }
74
+ },
75
+
76
+ {
77
+ "height": 6,
78
+ "width": 12,
79
+ "y": 9,
80
+ "x": 12,
81
+ "type": "metric",
82
+ "properties": {
83
+ "metrics": [
84
+ [ "funktor-testapp", "Duration", "Queue", "default" ],
85
+ [ "...", { "stat": "p99" } ],
86
+ [ "funktor-testapp", "Duration", "Queue", "low_concurrency" ],
87
+ [ "...", { "stat": "p99" } ]
88
+ ],
89
+ "view": "timeSeries",
90
+ "stacked": false,
91
+ "region": "us-east-1",
92
+ "stat": "Average",
93
+ "period": 60,
94
+ "title": "Job Duration by Queue"
95
+ }
96
+ },
97
+ {
98
+ "height": 6,
99
+ "width": 12,
100
+ "y": 9,
101
+ "x": 0,
102
+ "type": "metric",
103
+ "properties": {
104
+ "metrics": [
105
+ [ "funktor-testapp", "processed", "Queue", "default" ],
106
+ [ ".", "failed", ".", "." ],
107
+ [ "funktor-testapp", "processed", "Queue", "low_concurrency" ],
108
+ [ ".", "failed", ".", "." ]
109
+ ],
110
+ "view": "timeSeries",
111
+ "stacked": false,
112
+ "region": "us-east-1",
113
+ "title": "Process/Failed Jobs By Queue",
114
+ "period": 60,
115
+ "stat": "Sum"
116
+ }
117
+ },
118
+
119
+
120
+ {
121
+ "height": 3,
122
+ "width": 24,
123
+ "y": 9,
124
+ "x": 0,
125
+ "type": "text",
126
+ "properties": {
127
+ "markdown": "\n# Behind the scenes\n\n The stats below give some insight into the inner workings of the Funktor apparatus."
128
+ }
129
+ },
130
+
131
+
132
+
133
+
134
+ {
135
+ "height": 3,
136
+ "width": 6,
137
+ "y": 18,
138
+ "x": 0,
139
+ "type": "text",
140
+ "properties": {
141
+ "markdown": "\n# Incoming Jobs\n"
142
+ }
143
+ },
144
+ {
145
+ "height": 3,
146
+ "width": 3,
147
+ "y": 18,
148
+ "x": 6,
149
+ "type": "metric",
150
+ "properties": {
151
+ "metrics": [
152
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName", "${self:custom.funktor.IncomingJobQueueName}", { "label": "Messages Per Minute" } ]
153
+ ],
154
+ "view": "singleValue",
155
+ "region": "us-east-1",
156
+ "stat": "Sum",
157
+ "period": 60,
158
+ "title": "Messages Per Minute"
159
+ }
160
+ },
161
+ {
162
+ "height": 3,
163
+ "width": 15,
164
+ "y": 18,
165
+ "x": 9,
166
+ "type": "metric",
167
+ "properties": {
168
+ "metrics": [
169
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.IncomingJobHandlerName}", "Resource", "${self:custom.funktor.IncomingJobHandlerName}", { "label": "p10" } ],
170
+ [ "...", { "label": "p50", "stat": "p50" } ],
171
+ [ "...", { "label": "p99", "stat": "p99" } ],
172
+ [ "...", { "label": "Average", "stat": "Average" } ]
173
+ ],
174
+ "view": "singleValue",
175
+ "region": "us-east-1",
176
+ "stat": "p10",
177
+ "period": 60,
178
+ "title": "Handler Duration"
179
+ }
180
+ },
181
+
182
+
183
+
184
+ {
185
+ "height": 6,
186
+ "width": 9,
187
+ "y": 21,
188
+ "x": 0,
189
+ "type": "metric",
190
+ "properties": {
191
+ "metrics": [
192
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName", "${self:custom.funktor.IncomingJobQueueName}", { "label": "Received" } ],
193
+ [ ".", "NumberOfMessagesDeleted", ".", ".", { "label": "Handled" } ],
194
+ [ "AWS/Lambda", "Invocations", "FunctionName", "${self:custom.funktor.IncomingJobHandlerName}", "Resource", "${self:custom.funktor.IncomingJobHandlerName}", { "label": "Handler Invocations" } ],
195
+ [ "AWS/SQS", "ApproximateNumberOfMessagesVisible", "QueueName", "${self:custom.funktor.IncomingJobQueueName}", { "label": "Pending?" } ],
196
+ [ ".", "ApproximateNumberOfMessagesNotVisible", ".", ".", { "label": "Backlog?" } ],
197
+ [ ".", "NumberOfMessagesSent", ".", ".", { "label": "Sent" } ],
198
+ [ ".", "ApproximateNumberOfMessagesDelayed", ".", ".", { "label": "Delayed" } ]
199
+ ],
200
+ "view": "timeSeries",
201
+ "stacked": false,
202
+ "region": "us-east-1",
203
+ "title": "Incoming Job Queue (Async & scheduled jobs land here first)",
204
+ "period": 60,
205
+ "stat": "Sum",
206
+ "setPeriodToTimeRange": true,
207
+ "liveData": true
208
+ }
209
+ },
210
+ {
211
+ "height": 6,
212
+ "width": 9,
213
+ "y": 21,
214
+ "x": 9,
215
+ "type": "metric",
216
+ "properties": {
217
+ "period": 60,
218
+ "metrics": [
219
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.IncomingJobHandlerName}", { "stat": "Minimum" } ],
220
+ [ "...", { "stat": "Average" } ],
221
+ [ "...", { "stat": "Maximum" } ]
222
+ ],
223
+ "region": "us-east-1",
224
+ "title": "Incoming Job Handler Duration in Milliseconds",
225
+ "view": "timeSeries",
226
+ "stacked": false,
227
+ "liveData": true
228
+ }
229
+ },
230
+ {
231
+ "height": 3,
232
+ "width": 6,
233
+ "y": 21,
234
+ "x": 18,
235
+ "type": "metric",
236
+ "properties": {
237
+ "period": 60,
238
+ "metrics": [
239
+ [ "AWS/Lambda", "Errors", "FunctionName", "${self:custom.funktor.IncomingJobHandlerName}", { "id": "errors", "stat": "Sum", "color": "#d13212" } ],
240
+ [ ".", "Invocations", ".", ".", { "id": "invocations", "stat": "Sum", "visible": false } ],
241
+ [ { "expression": "100 - 100 * errors / MAX([errors, invocations])", "label": "Success rate (%)", "id": "availability", "yAxis": "right", "region": "us-east-1" } ]
242
+ ],
243
+ "region": "us-east-1",
244
+ "title": "Incoming Job Handler Error count and success rate (%)",
245
+ "yAxis": {
246
+ "right": {
247
+ "max": 100
248
+ }
249
+ },
250
+ "view": "timeSeries",
251
+ "stacked": false,
252
+ "liveData": true
253
+ }
254
+ },
255
+
256
+
257
+ {
258
+ "height": 3,
259
+ "width": 6,
260
+ "y": 24,
261
+ "x": 18,
262
+ "type": "metric",
263
+ "properties": {
264
+ "period": 60,
265
+ "metrics": [
266
+ [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName", "${self:custom.funktor.IncomingJobHandlerName}", { "stat": "Maximum" } ]
267
+ ],
268
+ "region": "us-east-1",
269
+ "title": "Incoming Job Handler Concurrent Executions",
270
+ "view": "timeSeries",
271
+ "stacked": false,
272
+ "liveData": true
273
+ }
274
+ },
275
+
276
+
277
+
278
+
279
+ {
280
+ "height": 3,
281
+ "width": 6,
282
+ "y": 27,
283
+ "x": 0,
284
+ "type": "text",
285
+ "properties": {
286
+ "markdown": "\n# Default Queue\n"
287
+ }
288
+ },
289
+ {
290
+ "height": 3,
291
+ "width": 3,
292
+ "y": 27,
293
+ "x": 6,
294
+ "type": "metric",
295
+ "properties": {
296
+ "metrics": [
297
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName",
298
+ "${self:custom.funktor.DefaultQueueName}", { "label": "Messages Per Minute" } ]
299
+ ],
300
+ "view": "singleValue",
301
+ "region": "us-east-1",
302
+ "stat": "Sum",
303
+ "period": 60,
304
+ "title": "Messages Per Minute"
305
+ }
306
+ },
307
+ {
308
+ "height": 3,
309
+ "width": 15,
310
+ "y": 27,
311
+ "x": 9,
312
+ "type": "metric",
313
+ "properties": {
314
+ "metrics": [
315
+ [ "AWS/Lambda", "Duration", "FunctionName",
316
+ "${self:custom.funktor.DefaultQueueHandlerName}", "Resource",
317
+ "${self:custom.funktor.DefaultQueueHandlerName}", { "label": "p10" } ],
318
+ [ "...", { "label": "p50", "stat": "p50" } ],
319
+ [ "...", { "label": "p99", "stat": "p99" } ],
320
+ [ "...", { "label": "Average", "stat": "Average" } ]
321
+ ],
322
+ "view": "singleValue",
323
+ "region": "us-east-1",
324
+ "stat": "p10",
325
+ "period": 60,
326
+ "title": "Handler Duration"
327
+ }
328
+ },
329
+ {
330
+ "height": 6,
331
+ "width": 9,
332
+ "y": 30,
333
+ "x": 0,
334
+ "type": "metric",
335
+ "properties": {
336
+ "metrics": [
337
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName",
338
+ "${self:custom.funktor.DefaultQueueName}",
339
+ { "label": "Received" } ],
340
+ [ ".", "NumberOfMessagesDeleted", ".", ".", { "label": "Handled" } ],
341
+ [ "AWS/Lambda", "Invocations", "FunctionName",
342
+ "${self:custom.funktor.DefaultQueueHandlerName}", "Resource",
343
+ "${self:custom.funktor.DefaultQueueHandlerName}", { "label": "Handler Invocations" } ],
344
+ [ "AWS/SQS", "ApproximateNumberOfMessagesVisible", "QueueName",
345
+ "${self:custom.funktor.DefaultQueueName}", { "label": "Pending?" } ],
346
+ [ ".", "ApproximateNumberOfMessagesNotVisible", ".", ".", { "label": "Backlog?" } ],
347
+ [ ".", "NumberOfMessagesSent", ".", ".", { "label": "Sent" } ],
348
+ [ ".", "ApproximateNumberOfMessagesDelayed", ".", ".", { "label": "Delayed" } ]
349
+ ],
350
+ "view": "timeSeries",
351
+ "stacked": false,
352
+ "region": "us-east-1",
353
+ "title": "Default Queue (Async jobs go here immediately, scheduled jobs land here in the minute before they're scheduled)",
354
+ "period": 60,
355
+ "stat": "Sum",
356
+ "liveData": true
357
+ }
358
+ },
359
+ {
360
+ "height": 6,
361
+ "width": 9,
362
+ "y": 30,
363
+ "x": 9,
364
+ "type": "metric",
365
+ "properties": {
366
+ "period": 60,
367
+ "metrics": [
368
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.DefaultQueueHandlerName}", { "stat": "Minimum" } ],
369
+ [ "...", { "stat": "Average" } ],
370
+ [ "...", { "stat": "Maximum" } ]
371
+ ],
372
+ "region": "us-east-1",
373
+ "title": "Default Queue Handler Duration in Milliseconds",
374
+ "view": "timeSeries",
375
+ "stacked": false,
376
+ "liveData": true
377
+ }
378
+ },
379
+ {
380
+ "height": 3,
381
+ "width": 6,
382
+ "y": 30,
383
+ "x": 18,
384
+ "type": "metric",
385
+ "properties": {
386
+ "period": 60,
387
+ "metrics": [
388
+ [ "AWS/Lambda", "Errors", "FunctionName",
389
+ "${self:custom.funktor.DefaultQueueHandlerName}", { "id": "errors", "stat": "Sum", "color": "#d13212" } ],
390
+ [ ".", "Invocations", ".", ".", { "id": "invocations", "stat": "Sum", "visible": false } ],
391
+ [ { "expression": "100 - 100 * errors / MAX([errors, invocations])", "label": "Success rate (%)", "id": "availability", "yAxis": "right", "region": "us-east-1" } ]
392
+ ],
393
+ "region": "us-east-1",
394
+ "title": "Default Queue Handler Error count and success rate (%)",
395
+ "yAxis": {
396
+ "right": {
397
+ "max": 100
398
+ }
399
+ },
400
+ "view": "timeSeries",
401
+ "stacked": false,
402
+ "liveData": true
403
+ }
404
+ },
405
+ {
406
+ "height": 3,
407
+ "width": 6,
408
+ "y": 33,
409
+ "x": 18,
410
+ "type": "metric",
411
+ "properties": {
412
+ "period": 60,
413
+ "metrics": [
414
+ [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName",
415
+ "${self:custom.funktor.DefaultQueueHandlerName}", { "stat": "Maximum" } ]
416
+ ],
417
+ "region": "us-east-1",
418
+ "title": "Default Queue Handler Concurrent executions",
419
+ "view": "timeSeries",
420
+ "stacked": false,
421
+ "liveData": true
422
+ }
423
+ },
424
+
425
+
426
+ {
427
+ "height": 3,
428
+ "width": 6,
429
+ "y": 36,
430
+ "x": 0,
431
+ "type": "text",
432
+ "properties": {
433
+ "markdown": "\n# LowConcurrency Queue\n"
434
+ }
435
+ },
436
+ {
437
+ "height": 3,
438
+ "width": 3,
439
+ "y": 36,
440
+ "x": 6,
441
+ "type": "metric",
442
+ "properties": {
443
+ "metrics": [
444
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName",
445
+ "${self:custom.funktor.LowConcurrencyQueueName}", { "label": "Messages Per Minute" } ]
446
+ ],
447
+ "view": "singleValue",
448
+ "region": "us-east-1",
449
+ "stat": "Sum",
450
+ "period": 60,
451
+ "title": "Messages Per Minute"
452
+ }
453
+ },
454
+ {
455
+ "height": 3,
456
+ "width": 15,
457
+ "y": 36,
458
+ "x": 9,
459
+ "type": "metric",
460
+ "properties": {
461
+ "metrics": [
462
+ [ "AWS/Lambda", "Duration", "FunctionName",
463
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", "Resource",
464
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", { "label": "p10" } ],
465
+ [ "...", { "label": "p50", "stat": "p50" } ],
466
+ [ "...", { "label": "p99", "stat": "p99" } ],
467
+ [ "...", { "label": "Average", "stat": "Average" } ]
468
+ ],
469
+ "view": "singleValue",
470
+ "region": "us-east-1",
471
+ "stat": "p10",
472
+ "period": 60,
473
+ "title": "Handler Duration"
474
+ }
475
+ },
476
+ {
477
+ "height": 6,
478
+ "width": 9,
479
+ "y": 39,
480
+ "x": 0,
481
+ "type": "metric",
482
+ "properties": {
483
+ "metrics": [
484
+ [ "AWS/SQS", "NumberOfMessagesReceived", "QueueName",
485
+ "${self:custom.funktor.LowConcurrencyQueueName}",
486
+ { "label": "Received" } ],
487
+ [ ".", "NumberOfMessagesDeleted", ".", ".", { "label": "Handled" } ],
488
+ [ "AWS/Lambda", "Invocations", "FunctionName",
489
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", "Resource",
490
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", { "label": "Handler Invocations" } ],
491
+ [ "AWS/SQS", "ApproximateNumberOfMessagesVisible", "QueueName",
492
+ "${self:custom.funktor.LowConcurrencyQueueName}", { "label": "Pending?" } ],
493
+ [ ".", "ApproximateNumberOfMessagesNotVisible", ".", ".", { "label": "Backlog?" } ],
494
+ [ ".", "NumberOfMessagesSent", ".", ".", { "label": "Sent" } ],
495
+ [ ".", "ApproximateNumberOfMessagesDelayed", ".", ".", { "label": "Delayed" } ]
496
+ ],
497
+ "view": "timeSeries",
498
+ "stacked": false,
499
+ "region": "us-east-1",
500
+ "title": "LowConcurrency Queue (Async jobs go here immediately, scheduled jobs land here in the minute before they're scheduled)",
501
+ "period": 60,
502
+ "stat": "Sum",
503
+ "liveData": true
504
+ }
505
+ },
506
+ {
507
+ "height": 6,
508
+ "width": 9,
509
+ "y": 39,
510
+ "x": 9,
511
+ "type": "metric",
512
+ "properties": {
513
+ "period": 60,
514
+ "metrics": [
515
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.LowConcurrencyQueueHandlerName}", { "stat": "Minimum" } ],
516
+ [ "...", { "stat": "Average" } ],
517
+ [ "...", { "stat": "Maximum" } ]
518
+ ],
519
+ "region": "us-east-1",
520
+ "title": "LowConcurrency Queue Handler Duration in Milliseconds",
521
+ "view": "timeSeries",
522
+ "stacked": false,
523
+ "liveData": true
524
+ }
525
+ },
526
+ {
527
+ "height": 3,
528
+ "width": 6,
529
+ "y": 39,
530
+ "x": 18,
531
+ "type": "metric",
532
+ "properties": {
533
+ "period": 60,
534
+ "metrics": [
535
+ [ "AWS/Lambda", "Errors", "FunctionName",
536
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", { "id": "errors", "stat": "Sum", "color": "#d13212" } ],
537
+ [ ".", "Invocations", ".", ".", { "id": "invocations", "stat": "Sum", "visible": false } ],
538
+ [ { "expression": "100 - 100 * errors / MAX([errors, invocations])", "label": "Success rate (%)", "id": "availability", "yAxis": "right", "region": "us-east-1" } ]
539
+ ],
540
+ "region": "us-east-1",
541
+ "title": "LowConcurrency Queue Handler Error count and success rate (%)",
542
+ "yAxis": {
543
+ "right": {
544
+ "max": 100
545
+ }
546
+ },
547
+ "view": "timeSeries",
548
+ "stacked": false,
549
+ "liveData": true
550
+ }
551
+ },
552
+ {
553
+ "height": 3,
554
+ "width": 6,
555
+ "y": 42,
556
+ "x": 18,
557
+ "type": "metric",
558
+ "properties": {
559
+ "period": 60,
560
+ "metrics": [
561
+ [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName",
562
+ "${self:custom.funktor.LowConcurrencyQueueHandlerName}", { "stat": "Maximum" } ]
563
+ ],
564
+ "region": "us-east-1",
565
+ "title": "LowConcurrency Queue Handler Concurrent executions",
566
+ "view": "timeSeries",
567
+ "stacked": false,
568
+ "liveData": true
569
+ }
570
+ },
571
+
572
+
573
+
574
+
575
+
576
+ {
577
+ "height": 3,
578
+ "width": 6,
579
+ "y": 45,
580
+ "x": 0,
581
+ "type": "text",
582
+ "properties": {
583
+ "markdown": "\n# Delayed Jobs\n"
584
+ }
585
+ },
586
+ {
587
+ "height": 3,
588
+ "width": 3,
589
+ "y": 45,
590
+ "x": 6,
591
+ "type": "metric",
592
+ "properties": {
593
+ "metrics": [
594
+ [ "AWS/DynamoDB", "ReturnedItemCount", "TableName", "${self:custom.funktor.JobsTableName}", "Operation", "Query" ]
595
+ ],
596
+ "view": "singleValue",
597
+ "region": "us-east-1",
598
+ "stat": "Average",
599
+ "period": 60,
600
+ "title": "Messages To Be Scheduled"
601
+ }
602
+ },
603
+ {
604
+ "height": 3,
605
+ "width": 15,
606
+ "y": 45,
607
+ "x": 9,
608
+ "type": "metric",
609
+ "properties": {
610
+ "metrics": [
611
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.JobActivatorName}", "Resource", "${self:custom.funktor.JobActivatorName}", { "label": "p10" } ],
612
+ [ "...", { "label": "p50", "stat": "p50" } ],
613
+ [ "...", { "label": "p99", "stat": "p99" } ],
614
+ [ "...", { "label": "Average", "stat": "Average" } ]
615
+ ],
616
+ "view": "singleValue",
617
+ "region": "us-east-1",
618
+ "stat": "p10",
619
+ "period": 60,
620
+ "title": "Handler Duration"
621
+ }
622
+ },
623
+
624
+
625
+
626
+
627
+ {
628
+ "height": 3,
629
+ "width": 6,
630
+ "y": 48,
631
+ "x": 18,
632
+ "type": "metric",
633
+ "properties": {
634
+ "period": 60,
635
+ "metrics": [
636
+ [ "AWS/Lambda", "Errors", "FunctionName", "${self:custom.funktor.JobActivatorName}", { "id": "errors", "stat": "Sum", "color": "#d13212" } ],
637
+ [ ".", "Invocations", ".", ".", { "id": "invocations", "stat": "Sum", "visible": false } ],
638
+ [ { "expression": "100 - 100 * errors / MAX([errors, invocations])", "label": "Success rate (%)", "id": "availability", "yAxis": "right", "region": "us-east-1" } ]
639
+ ],
640
+ "region": "us-east-1",
641
+ "title": "Delayed Job SchedulerError count and success rate (%)",
642
+ "yAxis": {
643
+ "right": {
644
+ "max": 100
645
+ }
646
+ },
647
+ "view": "timeSeries",
648
+ "stacked": false,
649
+ "liveData": true
650
+ }
651
+ },
652
+ {
653
+ "height": 3,
654
+ "width": 9,
655
+ "y": 48,
656
+ "x": 9,
657
+ "type": "metric",
658
+ "properties": {
659
+ "period": 60,
660
+ "metrics": [
661
+ [ "AWS/Lambda", "Duration", "FunctionName", "${self:custom.funktor.JobActivatorName}", { "stat": "Minimum" } ],
662
+ [ "...", { "stat": "Average" } ],
663
+ [ "...", { "stat": "Maximum" } ]
664
+ ],
665
+ "region": "us-east-1",
666
+ "title": "Delayed Job Scheduler Duration",
667
+ "view": "timeSeries",
668
+ "stacked": false,
669
+ "liveData": true
670
+ }
671
+ },
672
+ {
673
+ "height": 3,
674
+ "width": 9,
675
+ "y": 48,
676
+ "x": 0,
677
+ "type": "metric",
678
+ "properties": {
679
+ "metrics": [
680
+ [ "AWS/DynamoDB", "ReturnedItemCount", "TableName", "${self:custom.funktor.JobsTableName}", "Operation", "Query" ]
681
+ ],
682
+ "view": "timeSeries",
683
+ "stacked": false,
684
+ "region": "us-east-1",
685
+ "title": "Delayed Jobs To Be Executed In The Next 90 Seconds",
686
+ "period": 60,
687
+ "stat": "Average",
688
+ "liveData": true
689
+ }
690
+ },
691
+
692
+
693
+
694
+ {
695
+ "height": 3,
696
+ "width": 9,
697
+ "y": 51,
698
+ "x": 0,
699
+ "type": "metric",
700
+ "properties": {
701
+ "metrics": [
702
+ [ { "expression": "m2/PERIOD(m2)", "label": "Consumed Read Capacity Units", "id": "e1", "stat": "Sum", "region": "us-east-1" } ],
703
+ [ "AWS/DynamoDB", "ConsumedReadCapacityUnits", "TableName", "${self:custom.funktor.JobsTableName}", { "id": "m2", "visible": false } ],
704
+ [ ".", "ConsumedWriteCapacityUnits", ".", ".", { "yAxis": "left", "id": "m4", "visible": false } ],
705
+ [ ".", "WriteThrottleEvents", ".", ".", { "yAxis": "right", "id": "m5", "visible": false } ]
706
+ ],
707
+ "view": "timeSeries",
708
+ "stacked": false,
709
+ "region": "us-east-1",
710
+ "title": "Scheduled Job Table Read Capacity Units",
711
+ "period": 60,
712
+ "stat": "Sum",
713
+ "liveData": true
714
+ }
715
+ },
716
+ {
717
+ "height": 3,
718
+ "width": 6,
719
+ "y": 51,
720
+ "x": 18,
721
+ "type": "metric",
722
+ "properties": {
723
+ "period": 60,
724
+ "metrics": [
725
+ [ "AWS/Lambda", "ConcurrentExecutions", "FunctionName", "${self:custom.funktor.JobActivatorName}", { "stat": "Maximum" } ]
726
+ ],
727
+ "region": "us-east-1",
728
+ "title": "Delayd Job Schedule Concurrent executions",
729
+ "view": "timeSeries",
730
+ "stacked": false,
731
+ "liveData": true
732
+ }
733
+ },
734
+ {
735
+ "height": 3,
736
+ "width": 9,
737
+ "y": 51,
738
+ "x": 9,
739
+ "type": "metric",
740
+ "properties": {
741
+ "metrics": [
742
+ [ { "expression": "m4/PERIOD(m4)", "label": "Consumed Read Capacity Units", "id": "e1", "stat": "Sum", "region": "us-east-1" } ],
743
+ [ "AWS/DynamoDB", "ConsumedReadCapacityUnits", "TableName", "${self:custom.funktor.JobsTableName}", { "id": "m2", "visible": false } ],
744
+ [ ".", "ConsumedWriteCapacityUnits", ".", ".", { "yAxis": "left", "id": "m4", "visible": false } ],
745
+ [ ".", "WriteThrottleEvents", ".", ".", { "yAxis": "right", "id": "m5", "visible": false } ]
746
+ ],
747
+ "view": "timeSeries",
748
+ "stacked": false,
749
+ "region": "us-east-1",
750
+ "title": "Scheduled Job Table Write Capacity Units",
751
+ "period": 60,
752
+ "stat": "Sum",
753
+ "liveData": true
754
+ }
755
+ },
756
+
757
+
758
+
759
+
760
+ {
761
+ "height": 3,
762
+ "width": 18,
763
+ "y": 54,
764
+ "x": 0,
765
+ "type": "metric",
766
+ "properties": {
767
+ "metrics": [
768
+ [ "AWS/DynamoDB", "SuccessfulRequestLatency", "TableName", "${self:custom.funktor.JobsTableName}", "Operation", "PutItem", { "yAxis": "left" } ],
769
+ [ "...", "Query" ],
770
+ [ ".", "ThrottledRequests", ".", ".", ".", "PutItem", { "yAxis": "right", "visible": false } ],
771
+ [ ".", "SuccessfulRequestLatency", ".", ".", ".", "DeleteItem" ],
772
+ [ ".", "SuccessfulRequestLatency", ".", ".", ".", "UpdateItem" ],
773
+ [ ".", "ThrottledRequests", ".", ".", ".", ".", { "yAxis": "right", "visible": false } ]
774
+ ],
775
+ "view": "timeSeries",
776
+ "stacked": false,
777
+ "region": "us-east-1",
778
+ "stat": "Average",
779
+ "period": 60,
780
+ "title": "Scheduled Job Table Latency",
781
+ "liveData": true
782
+ }
783
+ },
784
+ {
785
+ "height": 3,
786
+ "width": 6,
787
+ "y": 54,
788
+ "x": 18,
789
+ "type": "metric",
790
+ "properties": {
791
+ "metrics": [
792
+ [ "AWS/DynamoDB", "ThrottledRequests", "TableName", "${self:custom.funktor.JobsTableName}", "Operation", "DeleteItem" ],
793
+ [ "...", "PutItem" ]
794
+ ],
795
+ "view": "timeSeries",
796
+ "stacked": false,
797
+ "region": "us-east-1",
798
+ "stat": "Sum",
799
+ "period": 60,
800
+ "title": "Scheduled Job Table Throttled Operations",
801
+ "liveData": true
802
+ }
803
+ }
804
+
805
+
806
+
807
+
808
+ ]
809
+ }