tj-scale 1.0.1 → 1.1.0
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/CHANGELOG.md +32 -0
- data/README.md +48 -48
- data/lib/tj-scale.rb +8 -5
- data/lib/tj_scale_ruby/configuration.rb +24 -4
- data/lib/tj_scale_ruby/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76a39f424b8bf07fbe1cd0812fa63833e403ce9c5983639e6f2644db2700b798
|
|
4
|
+
data.tar.gz: 78b517bd5a20e91d617dfbeddea44d085e1808442c24840034252b2140af286f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8995d5a220b907b77126f766c9f2c7b382cd445c8bd4f3da3b20509e072ef26e84092ee16462a0218693c211d44ad3f65769a10b421c639bdf0d02386a844a59
|
|
7
|
+
data.tar.gz: d534b2ceb99df75e41b4ee9b2495e00d5e0a105e2cdf9d3c579ef6202242d8ec953a1f71d8026a9f06359d6a03ba8c16dbc4123ac4dde9768dd34cb685d4a686
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.0] (tj-scale) - 2026-06-12
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Monitor process is now auto-detected from Heroku's `DYNO` env var**: `web.1`
|
|
15
|
+
monitors web and `worker.1` monitors worker, so one app monitors both process
|
|
16
|
+
types with no Procfile env prefixes or extra config. `TJ_SCALE_MONITOR_PROCESS`
|
|
17
|
+
still pins a single process type when set explicitly; off-Heroku (no `DYNO`)
|
|
18
|
+
the default remains `worker`. Non-web/worker dynos (`release.*`, `run.*`,
|
|
19
|
+
`scheduler.*`) never start the metrics loop.
|
|
20
|
+
- `target_process` (payload) follows the auto-detected process, so web samples
|
|
21
|
+
land on web scale rules and worker samples on worker rules automatically.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Custom process types**: any Heroku process type (e.g. `bulk-worker.1`) now
|
|
26
|
+
runs the monitor and reports job metrics under its own `target_process`, not
|
|
27
|
+
just `web`/`worker`. Platform dynos (`release`, `run`, `scheduler`, `console`,
|
|
28
|
+
`rake`) are excluded.
|
|
29
|
+
- **Per-process Sidekiq queue filter**: `TJ_SCALE_SIDEKIQ_QUEUES_<PROCESS>`
|
|
30
|
+
(process name upcased, non-alphanumerics → `_`, e.g.
|
|
31
|
+
`TJ_SCALE_SIDEKIQ_QUEUES_BULK_WORKER=low`) overrides the global
|
|
32
|
+
`TJ_SCALE_SIDEKIQ_QUEUES` for that process, so a bulk fleet can scale on its
|
|
33
|
+
own queue's backlog while the worker fleet scales on the rest.
|
|
34
|
+
|
|
35
|
+
## [1.0.2] (tj-scale) - 2026-06-12
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- README fully updated for the `tj-scale` name: install/build/publish instructions,
|
|
40
|
+
repository URLs (`Untechnickle/tj-scale-gem`), and generic example app names.
|
|
41
|
+
|
|
10
42
|
## [1.0.1] (tj-scale) - 2026-06-12
|
|
11
43
|
|
|
12
44
|
### Changed
|
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# tj-scale
|
|
2
2
|
|
|
3
3
|
[](https://www.ruby-lang.org/)
|
|
4
4
|
[](https://rubyonrails.org/)
|
|
5
5
|
[](LICENSE.txt)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
TJ Scale (`tj-scale`) is a Ruby gem that automatically monitors your background job queues — **Delayed Job or Sidekiq** — and your web traffic, and sends metrics to a remote monitoring service for auto-scaling purposes. It integrates seamlessly with Rails applications and Heroku deployments.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
@@ -28,7 +28,7 @@ The control plane lives in its own project, **`tj-scale-dashboard`** (a sibling
|
|
|
28
28
|
Add this line to your application's Gemfile:
|
|
29
29
|
|
|
30
30
|
```ruby
|
|
31
|
-
gem "tj-scale
|
|
31
|
+
gem "tj-scale", "~> 1.0"
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
And then execute:
|
|
@@ -40,7 +40,7 @@ $ bundle install
|
|
|
40
40
|
Or install it yourself as:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
$ gem install tj-scale
|
|
43
|
+
$ gem install tj-scale
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
### From Source
|
|
@@ -48,8 +48,8 @@ $ gem install tj-scale-ruby
|
|
|
48
48
|
1. Clone the repository:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
git clone https://github.com/
|
|
52
|
-
cd tj-scale-
|
|
51
|
+
git clone https://github.com/Untechnickle/tj-scale-gem.git
|
|
52
|
+
cd tj-scale-gem
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
2. Install dependencies:
|
|
@@ -85,7 +85,7 @@ Build the gem, publish or reference it, add it to your Rails app, and set config
|
|
|
85
85
|
cd /path/to/tj-scale
|
|
86
86
|
git init # if needed
|
|
87
87
|
git add .
|
|
88
|
-
git commit -m "Release tj-scale
|
|
88
|
+
git commit -m "Release tj-scale"
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
2. **Install dependencies and verify quality**:
|
|
@@ -101,10 +101,10 @@ Build the gem, publish or reference it, add it to your Rails app, and set config
|
|
|
101
101
|
4. **Build the package**:
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
gem build tj-scale
|
|
104
|
+
gem build tj-scale.gemspec
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
This produces `tj-scale
|
|
107
|
+
This produces `tj-scale-<version>.gem` in the current directory.
|
|
108
108
|
|
|
109
109
|
### 3. Publish the gem (choose one)
|
|
110
110
|
|
|
@@ -114,13 +114,13 @@ Build the gem, publish or reference it, add it to your Rails app, and set config
|
|
|
114
114
|
2. Push the file you built (version must match `VERSION`):
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
gem push tj-scale-
|
|
117
|
+
gem push tj-scale-1.0.1.gem
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
**Private gem host**
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
gem push tj-scale-
|
|
123
|
+
gem push tj-scale-1.0.1.gem --host https://your-gem-server.com
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
Configure Bundler in the app if your host needs authentication (see your provider’s docs).
|
|
@@ -130,9 +130,9 @@ Configure Bundler in the app if your host needs authentication (see your provide
|
|
|
130
130
|
In the app’s `Gemfile`:
|
|
131
131
|
|
|
132
132
|
```ruby
|
|
133
|
-
gem "tj-scale
|
|
133
|
+
gem "tj-scale", git: "https://github.com/Untechnickle/tj-scale-gem.git", branch: "main"
|
|
134
134
|
# or path for local development:
|
|
135
|
-
# gem "tj-scale
|
|
135
|
+
# gem "tj-scale", path: "../tj-scale"
|
|
136
136
|
```
|
|
137
137
|
|
|
138
138
|
Then `bundle install`.
|
|
@@ -142,7 +142,7 @@ Then `bundle install`.
|
|
|
142
142
|
1. Open the app’s **`Gemfile`** and add (adjust version or source as above):
|
|
143
143
|
|
|
144
144
|
```ruby
|
|
145
|
-
gem "tj-scale
|
|
145
|
+
gem "tj-scale", "~> 1.0"
|
|
146
146
|
```
|
|
147
147
|
|
|
148
148
|
2. Run:
|
|
@@ -153,7 +153,7 @@ Then `bundle install`.
|
|
|
153
153
|
|
|
154
154
|
3. **No extra `require`** is needed in `application.rb`: the gem registers a **Rails Railtie** and loads with Rails. Ensure your app already bundles its job backend — **`delayed_job_active_record`** or **`sidekiq`** (the gem auto-detects which one is loaded, or set `TJ_SCALE_JOB_BACKEND` explicitly).
|
|
155
155
|
|
|
156
|
-
4. Deploy or run the server as usual. The monitoring thread starts
|
|
156
|
+
4. Deploy or run the server as usual. The monitoring thread starts on **`web.1`** and **`worker.1`** automatically (process type auto-detected from Heroku's `DYNO`), so one app reports both web and worker metrics with no extra config. Set `TJ_SCALE_MONITOR_PROCESS` to pin a single process type (see below).
|
|
157
157
|
|
|
158
158
|
### 5. Configure environment variables
|
|
159
159
|
|
|
@@ -165,7 +165,7 @@ Configuration is **entirely via environment variables** (and Heroku **config var
|
|
|
165
165
|
| `TJ_SCALE_API_URL` | Yes | Full URL of the Agent API ingest path: **`POST /api/v1/metrics`** or **`POST /api/v1/sys-logs`** (same handler). Example local: `http://127.0.0.1:5001/api/v1/metrics`. |
|
|
166
166
|
| `TJ_SCALE_TARGET_APP` | No | Heroku app name to scale; defaults to **`HEROKU_APP_NAME`** if unset. |
|
|
167
167
|
| `TJ_SCALE_TARGET_PROCESS` | No | `web` or `worker` to scale; defaults to `TJ_SCALE_MONITOR_PROCESS`. |
|
|
168
|
-
| `TJ_SCALE_MONITOR_PROCESS` | No | `web` or `worker`
|
|
168
|
+
| `TJ_SCALE_MONITOR_PROCESS` | No | `web` or `worker` to pin the reporter to one process type. Default: auto-detected from `DYNO` (`web.1` reports web, `worker.1` reports worker); **`worker`** when `DYNO` is unset (non-Heroku). |
|
|
169
169
|
| `TJ_SCALE_INTERVAL_SECONDS` | No | Seconds between posts (default **20**). |
|
|
170
170
|
| `TJ_SCALE_JOB_BACKEND` | No | Queue backend for the **worker** reporter: `delayed_job`, `sidekiq`, or `auto` (default). `auto` uses Sidekiq when the `sidekiq` gem is loaded, otherwise Delayed Job. |
|
|
171
171
|
| `TJ_SCALE_SIDEKIQ_QUEUES` | No | Sidekiq backend only: comma-separated queue names to count (empty = all queues). |
|
|
@@ -177,26 +177,26 @@ Configuration is **entirely via environment variables** (and Heroku **config var
|
|
|
177
177
|
|
|
178
178
|
Heroku sets **`DYNO`** (for example `web.1`, `worker.1`) and typically **`HEROKU_APP_NAME`**; do not set **`DYNO`** manually in production.
|
|
179
179
|
|
|
180
|
-
**Example: `
|
|
180
|
+
**Example: `my-app-web` (web) and `my-app-workers` (workers)**
|
|
181
181
|
|
|
182
182
|
Use the same token on both apps if one backend handles scaling.
|
|
183
183
|
|
|
184
184
|
```bash
|
|
185
|
-
#
|
|
185
|
+
# my-app-web — reporter on web.1, scale web dynos
|
|
186
186
|
heroku config:set TJ_SCALE_API_TOKEN=your_token \
|
|
187
187
|
TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics \
|
|
188
|
-
TJ_SCALE_TARGET_APP=
|
|
188
|
+
TJ_SCALE_TARGET_APP=my-app-web \
|
|
189
189
|
TJ_SCALE_TARGET_PROCESS=web \
|
|
190
190
|
TJ_SCALE_MONITOR_PROCESS=web \
|
|
191
|
-
-a
|
|
191
|
+
-a my-app-web
|
|
192
192
|
|
|
193
|
-
#
|
|
193
|
+
# my-app-workers — reporter on worker.1, scale worker dynos
|
|
194
194
|
heroku config:set TJ_SCALE_API_TOKEN=your_token \
|
|
195
195
|
TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics \
|
|
196
|
-
TJ_SCALE_TARGET_APP=
|
|
196
|
+
TJ_SCALE_TARGET_APP=my-app-workers \
|
|
197
197
|
TJ_SCALE_TARGET_PROCESS=worker \
|
|
198
198
|
TJ_SCALE_MONITOR_PROCESS=worker \
|
|
199
|
-
-a
|
|
199
|
+
-a my-app-workers
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
On the **web** app, enable **`TJ_SCALE_ENABLE_QUEUE_TIME_MIDDLEWARE=1`** (and restart) so `queue_time_ms` is populated from Heroku’s router; the web dyno does not need a shared Delayed Job DB for that path.
|
|
@@ -214,7 +214,7 @@ The gem POSTs JSON with **`timestamp`**, **`heroku_app`**, **`target_process`**,
|
|
|
214
214
|
|
|
215
215
|
### 7. Verify
|
|
216
216
|
|
|
217
|
-
- At least one **web** dyno on `
|
|
217
|
+
- At least one **web** dyno on `my-app-web` and one **worker** dyno on `my-app-workers` so **`web.1`** and **`worker.1`** exist.
|
|
218
218
|
- Check **Rails logs** for `TjScaleRuby` lines (debug/warn/error).
|
|
219
219
|
- Confirm your API receives periodic requests with the expected payload.
|
|
220
220
|
|
|
@@ -272,31 +272,31 @@ heroku config:set TJ_SCALE_API_TOKEN=your_api_token_here
|
|
|
272
272
|
heroku config:set TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
-
The `DYNO` environment variable is automatically set by Heroku and is used to determine which
|
|
275
|
+
The `DYNO` environment variable is automatically set by Heroku and is used to determine which dynos run the monitoring loop: `web.1` and `worker.1` each report their own process type (override with `TJ_SCALE_MONITOR_PROCESS`).
|
|
276
276
|
|
|
277
|
-
### Example: web on `
|
|
277
|
+
### Example: web on `my-app-web`, workers on `my-app-workers`
|
|
278
278
|
|
|
279
279
|
Use two Heroku apps (or one app with both process types—same idea). Configure each app’s config vars so the **monitoring service** receives `heroku_app`, `target_process`, and `job_count` on each POST. Scaling bounds (min/max dynos) are set in the control plane's dashboard.
|
|
280
280
|
|
|
281
|
-
**App `
|
|
281
|
+
**App `my-app-web` (web dynos)** — run the reporter on the first web dyno and scale `web` dynos:
|
|
282
282
|
|
|
283
283
|
```bash
|
|
284
|
-
heroku config:set TJ_SCALE_API_TOKEN=your_token -a
|
|
285
|
-
heroku config:set TJ_SCALE_MONITOR_PROCESS=web -a
|
|
286
|
-
heroku config:set TJ_SCALE_TARGET_APP=
|
|
287
|
-
heroku config:set TJ_SCALE_TARGET_PROCESS=web -a
|
|
288
|
-
heroku config:set TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics -a
|
|
289
|
-
heroku config:set TJ_SCALE_ENABLE_QUEUE_TIME_MIDDLEWARE=1 -a
|
|
284
|
+
heroku config:set TJ_SCALE_API_TOKEN=your_token -a my-app-web
|
|
285
|
+
heroku config:set TJ_SCALE_MONITOR_PROCESS=web -a my-app-web
|
|
286
|
+
heroku config:set TJ_SCALE_TARGET_APP=my-app-web -a my-app-web
|
|
287
|
+
heroku config:set TJ_SCALE_TARGET_PROCESS=web -a my-app-web
|
|
288
|
+
heroku config:set TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics -a my-app-web
|
|
289
|
+
heroku config:set TJ_SCALE_ENABLE_QUEUE_TIME_MIDDLEWARE=1 -a my-app-web
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
-
**App `
|
|
292
|
+
**App `my-app-workers` (worker dynos)** — run the reporter on `worker.1` and scale `worker` dynos:
|
|
293
293
|
|
|
294
294
|
```bash
|
|
295
|
-
heroku config:set TJ_SCALE_API_TOKEN=your_token -a
|
|
296
|
-
heroku config:set TJ_SCALE_MONITOR_PROCESS=worker -a
|
|
297
|
-
heroku config:set TJ_SCALE_TARGET_APP=
|
|
298
|
-
heroku config:set TJ_SCALE_TARGET_PROCESS=worker -a
|
|
299
|
-
heroku config:set TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics -a
|
|
295
|
+
heroku config:set TJ_SCALE_API_TOKEN=your_token -a my-app-workers
|
|
296
|
+
heroku config:set TJ_SCALE_MONITOR_PROCESS=worker -a my-app-workers
|
|
297
|
+
heroku config:set TJ_SCALE_TARGET_APP=my-app-workers -a my-app-workers
|
|
298
|
+
heroku config:set TJ_SCALE_TARGET_PROCESS=worker -a my-app-workers
|
|
299
|
+
heroku config:set TJ_SCALE_API_URL=https://your-control-plane.example.com/api/v1/metrics -a my-app-workers
|
|
300
300
|
```
|
|
301
301
|
|
|
302
302
|
Ensure both apps have the `web` / `worker` process types in the `Procfile` as needed, deploy, and scale at least one dyno of each monitored type so `web.1` / `worker.1` exist.
|
|
@@ -307,7 +307,7 @@ Ensure both apps have the `web` / `worker` process types in the `Procfile` as ne
|
|
|
307
307
|
|
|
308
308
|
### Automatic Monitoring
|
|
309
309
|
|
|
310
|
-
Once installed and configured, the gem starts monitoring on the first dyno of
|
|
310
|
+
Once installed and configured, the gem starts monitoring on the first dyno of each process type (`web.1` and `worker.1`; pin one with `TJ_SCALE_MONITOR_PROCESS`). The loop runs every `TJ_SCALE_INTERVAL_SECONDS` (default 20) and POSTs metrics to the configured API.
|
|
311
311
|
|
|
312
312
|
### Manual Usage
|
|
313
313
|
|
|
@@ -338,7 +338,7 @@ ENV['TJ_MAX_PRIORITY'] = '10'
|
|
|
338
338
|
|
|
339
339
|
## How It Works
|
|
340
340
|
|
|
341
|
-
1. **Initialization**: When your Rails application starts, the `Railtie` checks if it's running on the first monitored
|
|
341
|
+
1. **Initialization**: When your Rails application starts, the `Railtie` checks if it's running on the first dyno of a monitored process type (`web.1` or `worker.1`, auto-detected from `DYNO`; `TJ_SCALE_MONITOR_PROCESS` pins one)
|
|
342
342
|
2. **Background Thread**: If conditions are met, a background thread is started
|
|
343
343
|
3. **Monitoring Loop**: Every N seconds (`TJ_SCALE_INTERVAL_SECONDS`), the thread POSTs a payload: on **worker** reporters it counts waiting jobs on the active backend; on **web** reporters it sends router queue time (middleware / env) plus request volume and average response time for the interval.
|
|
344
344
|
4. **Job counting (worker reporters, Delayed Job backend)**: `pending_job_count` filters jobs based on:
|
|
@@ -388,7 +388,7 @@ For a full checklist (git, tests, version, integrate in the app, Heroku), see **
|
|
|
388
388
|
3. Build the gem:
|
|
389
389
|
|
|
390
390
|
```bash
|
|
391
|
-
gem build tj-scale
|
|
391
|
+
gem build tj-scale.gemspec
|
|
392
392
|
```
|
|
393
393
|
|
|
394
394
|
This will create a `.gem` file in the current directory.
|
|
@@ -400,7 +400,7 @@ This will create a `.gem` file in the current directory.
|
|
|
400
400
|
3. Configure your credentials:
|
|
401
401
|
|
|
402
402
|
```bash
|
|
403
|
-
gem push --key your_api_key tj-scale-
|
|
403
|
+
gem push --key your_api_key tj-scale-1.0.1.gem
|
|
404
404
|
```
|
|
405
405
|
|
|
406
406
|
Or use the credentials file:
|
|
@@ -411,7 +411,7 @@ Or use the credentials file:
|
|
|
411
411
|
# ---
|
|
412
412
|
# :rubygems_api_key: your_api_key_here
|
|
413
413
|
|
|
414
|
-
gem push tj-scale-
|
|
414
|
+
gem push tj-scale-1.0.1.gem
|
|
415
415
|
```
|
|
416
416
|
|
|
417
417
|
### Publishing to a Private Gem Server
|
|
@@ -419,7 +419,7 @@ gem push tj-scale-ruby-1.0.0.gem
|
|
|
419
419
|
If you're using a private gem server:
|
|
420
420
|
|
|
421
421
|
```bash
|
|
422
|
-
gem push tj-scale-
|
|
422
|
+
gem push tj-scale-1.0.1.gem --host https://your-gem-server.com
|
|
423
423
|
```
|
|
424
424
|
|
|
425
425
|
## Deployment
|
|
@@ -429,7 +429,7 @@ gem push tj-scale-ruby-1.0.0.gem --host https://your-gem-server.com
|
|
|
429
429
|
1. Add the gem to your `Gemfile`:
|
|
430
430
|
|
|
431
431
|
```ruby
|
|
432
|
-
gem "tj-scale
|
|
432
|
+
gem "tj-scale", "~> 1.0"
|
|
433
433
|
```
|
|
434
434
|
|
|
435
435
|
2. Set the required environment variables:
|
|
@@ -469,7 +469,7 @@ The gem works with any Rails application. Just ensure:
|
|
|
469
469
|
|
|
470
470
|
## Contributing
|
|
471
471
|
|
|
472
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
472
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Untechnickle/tj-scale-gem.
|
|
473
473
|
|
|
474
474
|
1. Fork the repository
|
|
475
475
|
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
@@ -491,7 +491,7 @@ See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.
|
|
|
491
491
|
|
|
492
492
|
## Support
|
|
493
493
|
|
|
494
|
-
For issues, questions, or contributions, please open an issue on the [GitHub repository](https://github.com/
|
|
494
|
+
For issues, questions, or contributions, please open an issue on the [GitHub repository](https://github.com/Untechnickle/tj-scale-gem/issues).
|
|
495
495
|
|
|
496
496
|
## Authors
|
|
497
497
|
|
data/lib/tj-scale.rb
CHANGED
|
@@ -11,8 +11,10 @@ require "tj_scale_ruby/models/tj_scale_ruby"
|
|
|
11
11
|
# TJ Scale (the control plane) scales Heroku formation when ingested metrics cross rules
|
|
12
12
|
# you configure there. This gem only **reports signals**; it never calls Heroku directly.
|
|
13
13
|
#
|
|
14
|
-
# **Where it runs:** A single background thread on
|
|
15
|
-
# process
|
|
14
|
+
# **Where it runs:** A single background thread on the **first dyno of each process type**.
|
|
15
|
+
# The process is auto-detected from Heroku's +DYNO+ (`web.1` monitors web, `worker.1` monitors
|
|
16
|
+
# worker — so one app monitors both with no extra config). Set +TJ_SCALE_MONITOR_PROCESS+ to
|
|
17
|
+
# pin a single process type instead; off-Heroku (no +DYNO+) the default is `worker`.
|
|
16
18
|
#
|
|
17
19
|
# **What it sends:** On each tick (+TJ_SCALE_INTERVAL_SECONDS+), it POSTs JSON to
|
|
18
20
|
# +TJ_SCALE_API_URL+ (e.g. +/api/v1/metrics+ or +/api/v1/sys-logs+ — same handler on the
|
|
@@ -21,12 +23,12 @@ require "tj_scale_ruby/models/tj_scale_ruby"
|
|
|
21
23
|
# includes +heroku_app+ and +target_process+; scaling limits (min/max dynos) live in the
|
|
22
24
|
# control plane's settings, not in this gem.
|
|
23
25
|
#
|
|
24
|
-
# - **Worker monitor** (+
|
|
26
|
+
# - **Worker monitor** (on +worker.1+): counts waiting jobs
|
|
25
27
|
# (+job_count+, +queue_time_s+) on the configured queue backend — **Delayed Job** or **Sidekiq**,
|
|
26
28
|
# toggled with +TJ_SCALE_JOB_BACKEND+ (+delayed_job+ / +sidekiq+ / +auto+, the default, which
|
|
27
29
|
# prefers Sidekiq when loaded). Delayed Job needs +delayed_job_active_record+ and a shared DB;
|
|
28
30
|
# Sidekiq needs the +sidekiq+ gem and Redis (+TJ_SCALE_SIDEKIQ_QUEUES+ limits counted queues).
|
|
29
|
-
# - **Web monitor** (+
|
|
31
|
+
# - **Web monitor** (on +web.1+): sends +queue_time_ms+ from Rack middleware
|
|
30
32
|
# (router queue via +X-Request-Start+) when +TJ_SCALE_ENABLE_QUEUE_TIME_MIDDLEWARE=1+, plus
|
|
31
33
|
# request volume and average +response_time_ms+ for the tick. Without middleware, set
|
|
32
34
|
# +TJ_SCALE_QUEUE_TIME_MS+ or the platform will not scale on queue time until data exists.
|
|
@@ -69,7 +71,8 @@ module TjScaleRuby
|
|
|
69
71
|
end
|
|
70
72
|
end
|
|
71
73
|
|
|
72
|
-
# True when this dyno should run the metrics loop
|
|
74
|
+
# True when this dyno should run the metrics loop: the first dyno (.1) of the
|
|
75
|
+
# monitored process type (auto-detected from DYNO, or TJ_SCALE_MONITOR_PROCESS).
|
|
73
76
|
# Result is memoized; cleared by {.reset_configuration!}.
|
|
74
77
|
def self.monitor_on_this_dyno?
|
|
75
78
|
return @monitor_on_this_dyno if defined?(@monitor_on_this_dyno)
|
|
@@ -5,14 +5,21 @@ module TjScaleRuby
|
|
|
5
5
|
class Configuration
|
|
6
6
|
DEFAULT_INTERVAL_SECONDS = 20
|
|
7
7
|
JOB_BACKENDS = %w[auto delayed_job sidekiq].freeze
|
|
8
|
+
# Any Heroku process type (web, worker, bulk-worker, …) is monitorable;
|
|
9
|
+
# platform dynos never run app monitoring.
|
|
10
|
+
PROCESS_NAME = /\A[a-z][a-z0-9_-]*\z/
|
|
11
|
+
NON_APP_PROCESSES = %w[release run scheduler console rake].freeze
|
|
8
12
|
|
|
9
13
|
attr_reader :monitor_process, :interval_seconds,
|
|
10
14
|
:min_priority, :max_priority, :job_backend, :sidekiq_queues
|
|
11
15
|
|
|
12
16
|
def initialize(env = ENV)
|
|
13
|
-
@monitor_process = normalize_process(env["TJ_SCALE_MONITOR_PROCESS"]) ||
|
|
17
|
+
@monitor_process = normalize_process(env["TJ_SCALE_MONITOR_PROCESS"]) ||
|
|
18
|
+
process_from_dyno(env["DYNO"]) || "worker"
|
|
14
19
|
@job_backend = normalize_job_backend(env["TJ_SCALE_JOB_BACKEND"])
|
|
15
|
-
@sidekiq_queues = parse_list(
|
|
20
|
+
@sidekiq_queues = parse_list(
|
|
21
|
+
env[sidekiq_queues_key(@monitor_process)] || env["TJ_SCALE_SIDEKIQ_QUEUES"]
|
|
22
|
+
)
|
|
16
23
|
@interval_seconds = parse_positive_int(env["TJ_SCALE_INTERVAL_SECONDS"], DEFAULT_INTERVAL_SECONDS)
|
|
17
24
|
@target_app = nonempty_string(env["TJ_SCALE_TARGET_APP"])
|
|
18
25
|
@heroku_app_name = nonempty_string(env["HEROKU_APP_NAME"])
|
|
@@ -33,11 +40,24 @@ module TjScaleRuby
|
|
|
33
40
|
|
|
34
41
|
private
|
|
35
42
|
|
|
43
|
+
# Auto-detect from Heroku's DYNO (web.1 → web, worker.1 → worker) so one app
|
|
44
|
+
# can monitor both process types without per-process env. Nil off-Heroku and
|
|
45
|
+
# for non-web/worker dynos (release.1, run.x, scheduler.x).
|
|
46
|
+
def process_from_dyno(dyno)
|
|
47
|
+
normalize_process(dyno.to_s.split(".").first)
|
|
48
|
+
end
|
|
49
|
+
|
|
36
50
|
def normalize_process(value)
|
|
37
51
|
p = value.to_s.strip.downcase
|
|
38
|
-
return nil if p.empty?
|
|
52
|
+
return nil if p.empty? || NON_APP_PROCESSES.include?(p)
|
|
53
|
+
|
|
54
|
+
PROCESS_NAME.match?(p) ? p : nil
|
|
55
|
+
end
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
# Per-process Sidekiq queue filter, e.g. TJ_SCALE_SIDEKIQ_QUEUES_BULK_WORKER=low
|
|
58
|
+
# for a +bulk-worker+ process; falls back to TJ_SCALE_SIDEKIQ_QUEUES.
|
|
59
|
+
def sidekiq_queues_key(process)
|
|
60
|
+
"TJ_SCALE_SIDEKIQ_QUEUES_#{process.to_s.upcase.gsub(/[^A-Z0-9]/, '_')}"
|
|
41
61
|
end
|
|
42
62
|
|
|
43
63
|
# "delayed_job" | "sidekiq" | "auto" (default; detects from loaded gems).
|