chore-core 3.2.3 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +170 -153
- data/chore-core.gemspec +2 -3
- data/lib/chore.rb +20 -0
- data/lib/chore/cli.rb +1 -2
- data/lib/chore/configuration.rb +1 -1
- data/lib/chore/consumer.rb +41 -9
- data/lib/chore/job.rb +2 -0
- data/lib/chore/publisher.rb +18 -2
- data/lib/chore/queues/filesystem/consumer.rb +18 -13
- data/lib/chore/queues/filesystem/publisher.rb +1 -1
- data/lib/chore/queues/sqs.rb +22 -13
- data/lib/chore/queues/sqs/consumer.rb +61 -33
- data/lib/chore/queues/sqs/publisher.rb +26 -17
- data/lib/chore/strategies/consumer/batcher.rb +6 -6
- data/lib/chore/strategies/consumer/single_consumer_strategy.rb +5 -5
- data/lib/chore/strategies/consumer/threaded_consumer_strategy.rb +6 -6
- data/lib/chore/strategies/consumer/throttled_consumer_strategy.rb +10 -11
- data/lib/chore/strategies/worker/helpers/ipc.rb +0 -1
- data/lib/chore/unit_of_work.rb +2 -1
- data/lib/chore/version.rb +3 -3
- data/lib/chore/worker.rb +4 -4
- data/spec/chore/consumer_spec.rb +1 -1
- data/spec/chore/queues/filesystem/filesystem_consumer_spec.rb +5 -7
- data/spec/chore/queues/sqs/consumer_spec.rb +117 -76
- data/spec/chore/queues/sqs/publisher_spec.rb +49 -60
- data/spec/chore/queues/sqs_spec.rb +32 -41
- data/spec/chore/strategies/consumer/single_consumer_strategy_spec.rb +3 -3
- data/spec/chore/strategies/consumer/threaded_consumer_strategy_spec.rb +6 -6
- data/spec/chore/strategies/worker/forked_worker_strategy_spec.rb +1 -1
- data/spec/chore/strategies/worker/single_worker_strategy_spec.rb +1 -1
- data/spec/chore/worker_spec.rb +21 -21
- data/spec/spec_helper.rb +1 -1
- data/spec/support/queues/sqs/fake_objects.rb +18 -0
- metadata +9 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c18dd2782818f483d141ed7fff2daac3b9dacab
|
4
|
+
data.tar.gz: 78b658a9ad9b2e79126f194a56090e8e9da16d8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24ef03d8f8a42f2632073c2bfa4df9e466aa9fea90350f8df496dc117cae946aff83fcc1f4d458c00f1b8149067c85d3f990ebddac7b85d8d443901cf94062e9
|
7
|
+
data.tar.gz: 0925bbf1e586472db8a894116b2b9b6f4fe13c54941e250ae1006f400baf6fe35261314c63934c40d2f1b683dea2dd33c684d134f2edb07fecf7c1ae88001c48
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,92 +1,90 @@
|
|
1
|
-
# Chore: Job
|
1
|
+
# Chore: Async Job Processing Framework For Ruby
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/Tapjoy/chore.svg?branch=master)](https://travis-ci.org/Tapjoy/chore)
|
4
4
|
|
5
5
|
## About
|
6
6
|
|
7
|
-
Chore is a pluggable, multi-backend job
|
8
|
-
|
7
|
+
Chore is a pluggable, multi-backend job processing framework. It was built from the ground up to be extremely flexible.
|
8
|
+
We hope that you find integrating and using Chore to be as pleasant as we do.
|
9
9
|
|
10
|
-
The full docs for Chore can always be found at
|
10
|
+
The full docs for Chore can always be found at https://tapjoy.github.io/chore.
|
11
11
|
|
12
12
|
## Configuration
|
13
13
|
|
14
14
|
Chore can be integrated with any Ruby-based project by following these instructions:
|
15
15
|
|
16
|
-
|
16
|
+
1. Add `chore-core` to the Gemfile
|
17
17
|
|
18
|
-
|
18
|
+
```ruby
|
19
|
+
gem 'chore-core', '~> 4.0.0'
|
20
|
+
```
|
19
21
|
|
22
|
+
When using SQS, also add `dalli` to use for `memcached`-based deduplication:
|
23
|
+
|
24
|
+
```ruby
|
20
25
|
gem 'dalli'
|
26
|
+
```
|
21
27
|
|
22
|
-
Create a `Chorefile` file in the root of
|
28
|
+
1. Create a `Chorefile` file in the root of the project directory. While Chore itself can be configured from this file,
|
29
|
+
it's primarily used to direct the Chore binstub toward the root of the application so that it can locate all of the
|
30
|
+
dependencies and required code.
|
23
31
|
|
32
|
+
```
|
24
33
|
--require=./<FILE_TO_LOAD>
|
34
|
+
```
|
25
35
|
|
26
|
-
Make sure that `--require` points to the main entry point for
|
27
|
-
|
28
|
-
Other options include:
|
29
|
-
|
30
|
-
--concurrency 16 # number of concurrent worker processes, if using forked worker strategy
|
31
|
-
--worker-strategy Chore::Strategy::ForkedWorkerStrategy # which worker strategy class to use
|
32
|
-
--consumer Chore::Queues::SQS::Consumer # which consumer class to use Options are SQS::Consumer and Filesystem::Consumer. Filesystem is recommended for local and testing purposes only.
|
33
|
-
--consumer-strategy Chore::Queues::Strategies::Consumer::ThreadedConsumerStrategy # which consuming strategy to use. Options are SingleConsumerStrategy and ThreadedConsumerStrategy. Threaded is recommended for better tuning your consuming profile
|
34
|
-
--consumer-sleep-interval 1.0 # The amount of time in seconds to sleep when a consumer doesn't receive any messages. Sub-second values are accepted. The default varies by consumer implementation. This is a weak form of backoff for when there is no work to do.
|
35
|
-
--threads-per-queue 4 # number of threads per queue for consuming from a given queue.
|
36
|
-
--dedupe-servers # if using SQS or similiar queue with at-least once delivery and your memcache is running on something other than localhost
|
37
|
-
--batch-size 50 # how many messages are batched together before handing them to a worker
|
38
|
-
--batch-timeout 20 # maximum number of seconds to wait until handing a message over to a worker
|
39
|
-
--queue_prefix prefixy # A prefix to prepend to queue names, mainly for development and qa testing purposes
|
40
|
-
--max-attempts 100 # The maximum number of times a job can be attempted
|
41
|
-
--dupe-on-cache-failure # Determines the deduping behavior when a cache connection error occurs. When set to `false`, the message is assumed not to be a duplicate. Defaults to `false`.
|
42
|
-
--queue-polling-size 10 # If your particular queueing system supports responding with messages in batches of a certain size, you can control that with this flag. SQS has a built in upper-limit of 10, but other systems will vary.
|
36
|
+
Make sure that `--require` points to the main entry point for the application. If integrating with a Rails app,
|
37
|
+
point it to the application directory and Chore will handle loading the correct files on its own.
|
43
38
|
|
44
|
-
|
39
|
+
1. When using SQS, ensure that AWS credentials exist in the environment (e.g. but not limited to `AWS_ACCESS_KEY_ID` &
|
40
|
+
`AWS_SECRET_ACCESS_KEY` environment variables) and an AWS region is set (e.g. `AWS_REGION` environment variable) so that
|
41
|
+
Chore can authenticate with AWS.
|
45
42
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
By default, Chore will run over all queues it detects among the required files. If you wish to change this behavior, you can use:
|
43
|
+
By default, Chore will run over all queues it detects among the required files. If different behavior is desired,
|
44
|
+
use one of the following flags:
|
50
45
|
|
46
|
+
```
|
47
|
+
# Note that only one of these options may be used, not both. Chore will quit
|
48
|
+
# if both options are specified.
|
51
49
|
--queues QUEUE1,QUEUE2... # a list of queues to process
|
52
50
|
--except-queues QUEUE1,QUEUE2... # a list of queues _not_ to process
|
51
|
+
```
|
53
52
|
|
54
|
-
|
53
|
+
1. Chore has many more options, which can be viewed by executing `bundle exec chore --help`
|
55
54
|
|
56
|
-
### Tips
|
55
|
+
### Tips For Configuring Chore
|
57
56
|
|
58
|
-
For Rails, it can be necessary to add the
|
59
|
-
|
60
|
-
|
57
|
+
For Rails, it can be necessary to add the jobs directory to the eager loading path, found in `application.rb`. A similar
|
58
|
+
approach for most apps using jobs is likely needed, unless the jobs are placed into a directory that is already eager
|
59
|
+
loaded by the application. One example of this might be:
|
61
60
|
|
62
61
|
```ruby
|
63
62
|
config.eager_load_paths += File.join(config.root, "app", "jobs")
|
64
63
|
```
|
65
64
|
|
66
|
-
However, due to the way eager_load_paths works in Rails, this may only solve the issue
|
67
|
-
|
68
|
-
|
69
|
-
can choose to load the job files in any way you like:
|
65
|
+
However, due to the way `eager_load_paths` works in Rails, this may only solve the issue in the production environment.
|
66
|
+
It can also be useful useful for other environments to have something like this in an `config/initializers/chore.rb`
|
67
|
+
file, although the job files can be loaded in just about any way.
|
70
68
|
|
71
69
|
```ruby
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
if !Rails.env.production?
|
71
|
+
Dir["#{Rails.root}/app/jobs/**/*"].each do |file|
|
72
|
+
require file unless File.directory?(file)
|
73
|
+
end
|
74
|
+
end
|
75
75
|
```
|
76
76
|
|
77
|
-
### Producing
|
78
|
-
|
79
|
-
When it comes to configuring Chore, you have 2 main use cases - as a producer of messages, or as a consumer of messages (the consumer is also able to produce messages if need be, but is running as it's own isolated instance of your application).
|
80
|
-
|
81
|
-
For producers, you must do all of your Chore configuration in an intializer.
|
77
|
+
### Producing & Consuming Jobs
|
82
78
|
|
83
|
-
|
79
|
+
When it comes to configuring Chore, there are 2 main use configurations - as a producer of messages, or as a consumer of
|
80
|
+
messages. The consuming context may also messages if necessary, as it is running as its own isolated instance of the
|
81
|
+
application.
|
84
82
|
|
85
|
-
|
83
|
+
For producers, all of the Chore configuration must be in an initializer.
|
86
84
|
|
87
|
-
|
85
|
+
For consumers, a Chorefile must be used. A Chorefile _plus_ an initializer is also a good pattern.
|
88
86
|
|
89
|
-
|
87
|
+
Here's example of how to configure chore via an initializer:
|
90
88
|
|
91
89
|
```ruby
|
92
90
|
Chore.configure do |c|
|
@@ -99,27 +97,42 @@ Chore.configure do |c|
|
|
99
97
|
end
|
100
98
|
```
|
101
99
|
|
100
|
+
Because it is like that the same application serves as the basis for both producing and consuming messages, and there
|
101
|
+
will already be a considerable amount of configuration in the Producer, it makes sense to use Chorefile to simply
|
102
|
+
provide the `require` option and stick to the initializer for the rest of the configuration to keep things DRY.
|
103
|
+
|
104
|
+
However, like many aspects of Chore, it is ultimately up to the developer to decide which use case fits their needs
|
105
|
+
best. Chore is happy to be configured in almost any way a developer desires.
|
106
|
+
|
102
107
|
## Integration
|
103
108
|
|
104
|
-
|
109
|
+
This section assumes `foreman` is being used to execute (or export the run commands of) the application, but it is not
|
110
|
+
strictly necessary.
|
105
111
|
|
112
|
+
1. Add an appropriate line to the `Procfile`:
|
113
|
+
|
114
|
+
```
|
106
115
|
jobs: bundle exec chore -c config/chore.config
|
116
|
+
```
|
107
117
|
|
108
|
-
If
|
118
|
+
1. If the queues do not exist, they must be created before the application can produce/consume Chore jobs:
|
109
119
|
|
110
|
-
```ruby
|
111
|
-
require 'aws-sdk'
|
112
|
-
sqs =
|
113
|
-
sqs.
|
114
|
-
```
|
120
|
+
```ruby
|
121
|
+
require 'aws-sdk-sqs'
|
122
|
+
sqs = Aws::SQS::Client.new
|
123
|
+
sqs.create_queue(queue_name: "test_queue")
|
124
|
+
```
|
115
125
|
|
116
|
-
Finally, start
|
126
|
+
1. Finally, start the application as usual
|
117
127
|
|
128
|
+
```
|
118
129
|
bundle exec foreman start
|
130
|
+
```
|
119
131
|
|
120
|
-
## Chore::Job
|
132
|
+
## `Chore::Job`
|
121
133
|
|
122
|
-
A Chore::Job is any class
|
134
|
+
A `Chore::Job` is any class with `include Chore::Job` and implements a `perform(*args)` instance method. Here is an
|
135
|
+
example job class:
|
123
136
|
|
124
137
|
```ruby
|
125
138
|
class TestJob
|
@@ -129,30 +142,36 @@ class TestJob
|
|
129
142
|
def perform(args={})
|
130
143
|
Chore.logger.debug "My first async job"
|
131
144
|
end
|
132
|
-
|
133
145
|
end
|
134
146
|
```
|
135
147
|
|
136
|
-
This job declares that the name of the queue it uses is `test_queue`, set in the queue_options method.
|
148
|
+
This job declares that the name of the queue it uses is `test_queue`, set in the `queue_options` method.
|
149
|
+
|
150
|
+
### `Chore::Job` & `perform` Signatures
|
137
151
|
|
138
|
-
|
152
|
+
The perform method signature can have explicit argument names, but in practice this makes changing the signature more
|
153
|
+
difficult later on. Once a `Chore::Job` is in production and being used at a constant rate, it becomes problematic to
|
154
|
+
begin mixing versions of the job with non-matching signatures.
|
139
155
|
|
140
|
-
|
156
|
+
While this is able to be overcome with a number of techniques, such as versioning jobs/queues, it increases the
|
157
|
+
complexity of making changes.
|
141
158
|
|
142
|
-
|
159
|
+
The simplest way to structure job signatures is to treat the arguments as a hash. This enables maintaining forwards and
|
160
|
+
backwards compatibility between signature changes with the same job class.
|
143
161
|
|
144
|
-
|
162
|
+
However, Chore is ultimately agnostic in this regard and will allow explicit arguments in signatures as easily as using
|
163
|
+
a simple hash; the choice is left to the developer.
|
145
164
|
|
146
|
-
|
165
|
+
### `Chore::Job` & Publishing Jobs
|
147
166
|
|
148
|
-
|
167
|
+
Now that there's a test job, publishing an instance of the job is as simple as:
|
149
168
|
|
150
|
-
Now that you've got a test job, if you wanted to publish to that job it's as simple as:
|
151
169
|
```ruby
|
152
170
|
TestJob.perform_async({"message"=>"YES, DO THAT THING."})
|
153
171
|
```
|
154
172
|
|
155
|
-
It's advisable to specify the Publisher
|
173
|
+
It's advisable to specify the Publisher Chore uses to send messages globally, so that it can easily be modified based on
|
174
|
+
the environment. To do this, add a configuration block to an initializer:
|
156
175
|
|
157
176
|
```ruby
|
158
177
|
Chore.configure do |c|
|
@@ -160,14 +179,15 @@ Chore.configure do |c|
|
|
160
179
|
end
|
161
180
|
```
|
162
181
|
|
163
|
-
It is worth noting that any option that can be set via config file or command-line args can also be set in a configure
|
182
|
+
It is worth noting that any option that can be set via config file or command-line args can also be set in a configure
|
183
|
+
block.
|
164
184
|
|
165
185
|
If a global publisher is set, it can be overridden on a per-job basis by specifying the publisher in `queue_options`.
|
166
186
|
|
167
187
|
## Retry Backoff Strategy
|
168
188
|
|
169
|
-
Chore has basic support for delaying retries
|
170
|
-
supports this functionality is SQS
|
189
|
+
Chore has basic support for delaying retries of a failed job using a step function. Currently the only queue that
|
190
|
+
supports this functionality is SQS; all others will simply ignore the delay setting.
|
171
191
|
|
172
192
|
### Setup
|
173
193
|
|
@@ -179,51 +199,52 @@ queue_options :name => 'nameOfQueue',
|
|
179
199
|
:backoff => lambda { |work| work.current_attempt ** 2 } # Exponential backoff
|
180
200
|
```
|
181
201
|
|
182
|
-
### Using
|
202
|
+
### Using The Backoff
|
183
203
|
|
184
204
|
If there is a `:backoff` option supplied, any failures will delay the next attempt by the result of that lambda.
|
185
205
|
|
186
|
-
### Notes
|
206
|
+
### Notes On SQS & Delays
|
187
207
|
|
188
|
-
Read more details about SQS and Delays [here](docs/Delayed
|
208
|
+
Read more details about SQS and Delays [here](docs/Delayed%20Jobs.md)
|
189
209
|
|
190
210
|
## Hooks
|
191
211
|
|
192
|
-
A number of hooks, both global and per-job, exist in Chore for
|
212
|
+
A number of hooks, both global and per-job, exist in Chore for flexibility and convencience. Hooks should be named
|
213
|
+
`hook_name_identifier` where `identifier` is a descriptive string of chosen by the developer.
|
193
214
|
|
194
|
-
Global Hooks
|
215
|
+
### Global Hooks
|
195
216
|
|
196
|
-
* before_start
|
197
|
-
* before_first_fork
|
198
|
-
* before_fork
|
199
|
-
* after_fork
|
200
|
-
* around_fork
|
201
|
-
* within_fork
|
202
|
-
*
|
217
|
+
* `before_start`
|
218
|
+
* `before_first_fork`
|
219
|
+
* `before_fork`
|
220
|
+
* `after_fork`
|
221
|
+
* `around_fork`
|
222
|
+
* `within_fork`
|
223
|
+
* behaves similarly to `around_fork`, except that it is called _after_ the worker process has been forked.
|
224
|
+
In contrast, `around_fork` is called by the parent process ( chore-master`)
|
225
|
+
* `before_shutdown`
|
203
226
|
|
204
|
-
|
227
|
+
## Filesystem Consumer/Publisher Hooks
|
205
228
|
|
206
|
-
|
229
|
+
* `on_fetch(job_file, job_json)`
|
207
230
|
|
208
|
-
|
231
|
+
#### SQS Consumer Hooks
|
209
232
|
|
210
|
-
|
233
|
+
* `on_fetch(handle, body)`
|
211
234
|
|
212
|
-
|
235
|
+
### Per Job
|
213
236
|
|
214
|
-
|
215
|
-
|
216
|
-
*
|
217
|
-
*
|
218
|
-
*
|
219
|
-
*
|
220
|
-
*
|
221
|
-
* on_failure(message, error)
|
222
|
-
* on_permanent_failure(queue_name, message, error)
|
237
|
+
* `before_publish`
|
238
|
+
* `after_publish`
|
239
|
+
* `before_perform(message)`
|
240
|
+
* `after_perform(message)`
|
241
|
+
* `on_rejected(message)`
|
242
|
+
* `on_failure(message, error)`
|
243
|
+
* `on_permanent_failure(queue_name, message, error)`
|
223
244
|
|
224
245
|
All per-job hooks can also be global hooks.
|
225
246
|
|
226
|
-
Hooks can be added to a job class
|
247
|
+
Hooks can be added to a job class like so:
|
227
248
|
|
228
249
|
```ruby
|
229
250
|
class TestJob
|
@@ -239,56 +260,52 @@ class TestJob
|
|
239
260
|
end
|
240
261
|
end
|
241
262
|
```
|
263
|
+
|
242
264
|
Global hooks can also be registered like so:
|
243
265
|
|
244
266
|
```ruby
|
245
267
|
Chore.add_hook :after_publish do
|
246
|
-
#
|
268
|
+
# Add handler code here
|
247
269
|
end
|
248
270
|
```
|
249
271
|
|
250
272
|
## Signals
|
251
273
|
|
252
|
-
Signal handling can get complicated when
|
253
|
-
|
274
|
+
Signal handling can get complicated when there are multiple threads, process forks, and both signal handlers and
|
275
|
+
application code making use of mutexes.
|
254
276
|
|
255
|
-
To simplify the complexities around this, Chore introduces some additional
|
256
|
-
|
257
|
-
functionality is primarily inspired by sidekiq's signal handling @
|
277
|
+
To simplify the complexities around this, Chore introduces some additional behaviors on top of Ruby's default
|
278
|
+
`Signal.trap` implementation. This functionality is primarily inspired by `sidekiq`'s signal handling @
|
258
279
|
https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/cli.rb.
|
259
280
|
|
260
|
-
In particular
|
261
|
-
|
262
|
-
on the differences between Ruby's `Signal.trap` and Chore's `Chore::Signal.trap`.
|
281
|
+
In particular Chore handles signals in a separate thread, and does so sequentially instead of being interrupt-driven.
|
282
|
+
See `Chore::Signal` for more details on the differences between Ruby's `Signal.trap` and Chore's `Chore::Signal.trap`.
|
263
283
|
|
264
|
-
Chore will respond to the following
|
284
|
+
Chore will respond to the following signals:
|
265
285
|
|
266
|
-
* INT , TERM
|
267
|
-
|
286
|
+
* `INT` , `TERM`, `QUIT` - Chore will begin shutting down, taking steps to safely terminate workers and not interrupt
|
287
|
+
jobs in progress unless it believes they may be hung
|
288
|
+
* `USR1` - Re-opens logfiles, useful for handling log rotations
|
268
289
|
|
269
290
|
## Timeouts
|
270
291
|
|
271
|
-
When using the forked worker strategy for processing jobs, inevitably there are
|
272
|
-
|
273
|
-
hung network calls, tight loops, etc. When these jobs hang, they consume
|
292
|
+
When using the forked worker strategy for processing jobs, inevitably there are cases in which child processes become
|
293
|
+
stuck. This could result from deadlocks, hung network calls, tight loops, etc. When these jobs hang, they consume
|
274
294
|
resources and can affect throughput.
|
275
295
|
|
276
|
-
To mitigate this, Chore has built-in monitoring of forked child processes.
|
277
|
-
|
278
|
-
|
279
|
-
a KILL signal.
|
296
|
+
To mitigate this, Chore has built-in monitoring of forked child processes. When a fork is created to process a batch of
|
297
|
+
work, that fork is assigned an expiration time -- if it doesn't complete by that time, the process is sent a `KILL`
|
298
|
+
signal.
|
280
299
|
|
281
300
|
Fork expiration times are determined from one of two places:
|
282
|
-
1. The timeout associated with the queue. For SQS, this is the visibility
|
283
|
-
timeout.
|
284
|
-
2. The default queue timeout configured for Chore. For Filesystem queues,
|
285
|
-
this is the value used.
|
286
301
|
|
287
|
-
|
288
|
-
|
302
|
+
1. The timeout associated with the queue. For SQS queues, this is the visibility timeout.
|
303
|
+
1. The default queue timeout configured for Chore. For filesystem queues, this is the value used.
|
289
304
|
|
290
|
-
|
291
|
-
the
|
305
|
+
For example, if a worker is processing a batch of 5 jobs and each job's queue has a timeout of 60s, then the expiration
|
306
|
+
time will be 5 minutes for the worker.
|
307
|
+
|
308
|
+
To change the default queue timeout (when one can't be inferred), do the following:
|
292
309
|
|
293
310
|
```ruby
|
294
311
|
Chore.configure do |c|
|
@@ -296,62 +313,62 @@ Chore.configure do |c|
|
|
296
313
|
end
|
297
314
|
```
|
298
315
|
|
299
|
-
A reasonable timeout would be based on the maximum amount of time
|
300
|
-
|
301
|
-
get killed if the job is running for too long.
|
316
|
+
A reasonable timeout would be based on the maximum amount of time any job in the system is expected to run. Keep in
|
317
|
+
mind that the process running the job may get killed if the job is running for too long.
|
302
318
|
|
303
319
|
## Plugins
|
304
320
|
|
305
|
-
Chore has several plugin gems available, which extend
|
321
|
+
Chore has several plugin gems available, which extend its core functionality
|
306
322
|
|
307
323
|
[New Relic](https://github.com/Tapjoy/chore-new_relic) - Integrating Chore with New Relic
|
308
324
|
|
309
325
|
[Airbrake](https://github.com/Tapjoy/chore-airbrake) - Integrating Chore with Airbrake
|
310
326
|
|
311
|
-
## Managing Chore
|
327
|
+
## Managing Chore Processes
|
312
328
|
|
313
329
|
### Sample Upstart
|
314
330
|
|
315
|
-
There are lots of ways to create upstart scripts, so it's difficult to give a prescriptive
|
316
|
-
|
317
|
-
at Tapjoy:
|
331
|
+
There are lots of ways to create upstart scripts, so it's difficult to give a prescriptive example of the "right" way to
|
332
|
+
do it. However, here are some ideas from how we run it in production at Tapjoy:
|
318
333
|
|
319
|
-
|
320
|
-
|
334
|
+
For security reasons, a specific user should be specified that the process runs as. Switch to this user at the beginning
|
335
|
+
of the exec line
|
321
336
|
|
322
337
|
```bash
|
323
338
|
su - $USER --command '...'
|
324
339
|
```
|
325
340
|
|
326
|
-
For the command to run Chore itself keeping all of the necessary environment variables in an env
|
327
|
-
|
328
|
-
|
341
|
+
For the command to run Chore itself keeping all of the necessary environment variables in an env file that Upstart can
|
342
|
+
source on it's exec line, to prevent having to mix changing environment variables with having to change the upstart
|
343
|
+
script itself
|
329
344
|
|
330
345
|
```bash
|
331
346
|
source $PATHTOENVVARS ;
|
332
347
|
```
|
333
348
|
|
334
|
-
After that,
|
335
|
-
|
336
|
-
|
349
|
+
After that, ensure Chore is running under the right ruby version. Additionally, `STDOUT` and `STDERR` can be redirected
|
350
|
+
to `logger` with an app name. This makes it easy to find information in syslog later on. Putting that all together looks
|
351
|
+
like:
|
337
352
|
|
338
353
|
```bash
|
339
354
|
rvm use $RUBYVERSION do bundle exec chore -c Chorefile 2>&1 | logger -t $APPNAME
|
340
355
|
```
|
341
356
|
|
342
|
-
There are many other ways
|
343
|
-
|
357
|
+
There are many other ways to manage the Upstart file, but these are a few of the ways we prefer to do it. Putting it all
|
358
|
+
together, it looks something like:
|
344
359
|
|
345
360
|
```bash
|
346
|
-
exec su - special_user --command '
|
361
|
+
exec su - special_user --command '\
|
362
|
+
source /the/path/to/env ;\
|
363
|
+
rvm use 2.4.1 do bundle exec chore -c Chorefile 2>&1 | logger chore-app ;'
|
347
364
|
```
|
348
365
|
|
349
366
|
### Locating Processes
|
350
367
|
|
351
|
-
As Chore does not keep a
|
352
|
-
|
368
|
+
As Chore does not keep a PID file, and has both a master and a potential number of workers, it may be difficult to
|
369
|
+
isolate the exact PID for the master process.
|
353
370
|
|
354
|
-
To find Chore master processes via
|
371
|
+
To find Chore master processes via `ps`, run the following:
|
355
372
|
|
356
373
|
```bash
|
357
374
|
ps aux | grep bin/chore
|
@@ -366,15 +383,15 @@ pgrep -f bin/chore
|
|
366
383
|
To find a list of only Chore worker processes:
|
367
384
|
|
368
385
|
```bash
|
369
|
-
ps aux | grep chore-
|
386
|
+
ps aux | grep chore-worker
|
370
387
|
```
|
371
388
|
|
372
389
|
or
|
373
390
|
|
374
391
|
```bash
|
375
|
-
pgrep -f chore-
|
392
|
+
pgrep -f chore-worker
|
376
393
|
```
|
394
|
+
|
377
395
|
## Copyright
|
378
396
|
|
379
|
-
Copyright (c) 2013 -
|
380
|
-
further details.
|
397
|
+
Copyright (c) 2013 - 2020 Tapjoy. See [LICENSE.txt](LICENSE.txt) for further details.
|