yabeda-sidekiq 0.1.4 → 0.8.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/.github/workflows/build-release.yml +82 -0
- data/.github/workflows/test.yml +47 -0
- data/.rubocop.yml +24 -3
- data/CHANGELOG.md +47 -0
- data/Gemfile +1 -1
- data/README.md +90 -3
- data/Rakefile +4 -1
- data/lib/yabeda/sidekiq.rb +63 -18
- data/lib/yabeda/sidekiq/config.rb +18 -0
- data/lib/yabeda/sidekiq/server_middleware.rb +13 -4
- data/lib/yabeda/sidekiq/version.rb +1 -1
- data/yabeda-sidekiq.gemspec +5 -3
- metadata +47 -11
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68116758a02a4497a4eda56cac585a5afcfac8902e880d1c061c70f952898ed0
|
4
|
+
data.tar.gz: 599d85f03c0a5cc8ef87c78db670337263cc1eecb4dd14ee0925aa0862b07e12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f86db733e71ce0b21e1997714124d55cb97774d3076e9d2c5d7b2a014f741973d185b92bcd3fc7eb34e57d1ee5de6a696266129663557a327f424b8eda308d30
|
7
|
+
data.tar.gz: ebfb0e1814c4e9b31f0fb130028fb764b8014688a0c70add91e04282d57de545dd32de37bcfa42d266d7defb081e016060007e90ce61908443234fcdcff557ba
|
@@ -0,0 +1,82 @@
|
|
1
|
+
name: Build and release gem to RubyGems
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v*
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
release:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
with:
|
14
|
+
fetch-depth: 0 # Fetch current tag as annotated. See https://github.com/actions/checkout/issues/290
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: 2.7
|
18
|
+
- name: "Extract data from tag: version, message, body"
|
19
|
+
id: tag
|
20
|
+
run: |
|
21
|
+
git fetch --tags --force # Really fetch annotated tag. See https://github.com/actions/checkout/issues/290#issuecomment-680260080
|
22
|
+
echo ::set-output name=version::${GITHUB_REF#refs/tags/v}
|
23
|
+
echo ::set-output name=subject::$(git for-each-ref $GITHUB_REF --format='%(contents:subject)')
|
24
|
+
BODY="$(git for-each-ref $GITHUB_REF --format='%(contents:body)')"
|
25
|
+
# Extract changelog entries between this and previous version headers
|
26
|
+
escaped_version=$(echo ${GITHUB_REF#refs/tags/v} | sed -e 's/[]\/$*.^[]/\\&/g')
|
27
|
+
changelog=$(awk "BEGIN{inrelease=0} /## ${escaped_version}/{inrelease=1;next} /## [0-9]+\.[0-9]+\.[0-9]+/{inrelease=0;exit} {if (inrelease) print}" CHANGELOG.md)
|
28
|
+
# Multiline body for release. See https://github.community/t/set-output-truncates-multiline-strings/16852/5
|
29
|
+
BODY="${BODY}"$'\n'"${changelog}"
|
30
|
+
BODY="${BODY//'%'/'%25'}"
|
31
|
+
BODY="${BODY//$'\n'/'%0A'}"
|
32
|
+
BODY="${BODY//$'\r'/'%0D'}"
|
33
|
+
echo "::set-output name=body::$BODY"
|
34
|
+
# Add pre-release option if tag name has any suffix after vMAJOR.MINOR.PATCH
|
35
|
+
if [[ ${GITHUB_REF#refs/tags/} =~ ^v[0-9]+\.[0-9]+\.[0-9]+.+ ]]; then
|
36
|
+
echo ::set-output name=prerelease::true
|
37
|
+
fi
|
38
|
+
- name: Build gem
|
39
|
+
run: gem build
|
40
|
+
- name: Calculate checksums
|
41
|
+
run: sha256sum yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem > SHA256SUM
|
42
|
+
- name: Check version
|
43
|
+
run: ls -l yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem
|
44
|
+
- name: Create Release
|
45
|
+
id: create_release
|
46
|
+
uses: actions/create-release@v1
|
47
|
+
env:
|
48
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
49
|
+
with:
|
50
|
+
tag_name: ${{ github.ref }}
|
51
|
+
release_name: ${{ steps.tag.outputs.subject }}
|
52
|
+
body: ${{ steps.tag.outputs.body }}
|
53
|
+
draft: false
|
54
|
+
prerelease: ${{ steps.tag.outputs.prerelease }}
|
55
|
+
- name: Upload built gem as release asset
|
56
|
+
uses: actions/upload-release-asset@v1
|
57
|
+
env:
|
58
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
59
|
+
with:
|
60
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
61
|
+
asset_path: yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem
|
62
|
+
asset_name: yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem
|
63
|
+
asset_content_type: application/x-tar
|
64
|
+
- name: Upload checksums as release asset
|
65
|
+
uses: actions/upload-release-asset@v1
|
66
|
+
env:
|
67
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
68
|
+
with:
|
69
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
70
|
+
asset_path: SHA256SUM
|
71
|
+
asset_name: SHA256SUM
|
72
|
+
asset_content_type: text/plain
|
73
|
+
- name: Publish to GitHub packages
|
74
|
+
env:
|
75
|
+
GEM_HOST_API_KEY: Bearer ${{ secrets.GITHUB_TOKEN }}
|
76
|
+
run: |
|
77
|
+
gem push yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem --host https://rubygems.pkg.github.com/${{ github.repository_owner }}
|
78
|
+
- name: Publish to RubyGems
|
79
|
+
env:
|
80
|
+
GEM_HOST_API_KEY: "${{ secrets.RUBYGEMS_API_KEY }}"
|
81
|
+
run: |
|
82
|
+
gem push yabeda-sidekiq-${{ steps.tag.outputs.version }}.gem
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: Run tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- '**'
|
8
|
+
tags-ignore:
|
9
|
+
- 'v*'
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
name: "Run tests"
|
14
|
+
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
strategy:
|
17
|
+
fail-fast: false
|
18
|
+
matrix:
|
19
|
+
include:
|
20
|
+
- ruby: 3.0
|
21
|
+
- ruby: 2.7
|
22
|
+
- ruby: 2.6
|
23
|
+
- ruby: 2.5
|
24
|
+
container:
|
25
|
+
image: ruby:${{ matrix.ruby }}
|
26
|
+
env:
|
27
|
+
CI: true
|
28
|
+
steps:
|
29
|
+
- uses: actions/checkout@v2
|
30
|
+
- uses: actions/cache@v2
|
31
|
+
with:
|
32
|
+
path: vendor/bundle
|
33
|
+
key: bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}-${{ hashFiles('**/Gemfile') }}
|
34
|
+
restore-keys: |
|
35
|
+
bundle-${{ matrix.ruby }}-${{ hashFiles('**/*.gemspec') }}-${{ hashFiles('**/Gemfile') }}
|
36
|
+
bundle-${{ matrix.ruby }}-
|
37
|
+
- name: Upgrade Bundler to 2.0 (for older Rubies)
|
38
|
+
run: gem install bundler -v '~> 2.0'
|
39
|
+
- name: Bundle install
|
40
|
+
run: |
|
41
|
+
bundle config path vendor/bundle
|
42
|
+
bundle install
|
43
|
+
bundle update
|
44
|
+
- name: Run Rubocop
|
45
|
+
run: bundle exec rubocop
|
46
|
+
- name: Run RSpec
|
47
|
+
run: bundle exec rspec
|
data/.rubocop.yml
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
---
|
2
2
|
require:
|
3
|
-
- rubocop-rspec
|
3
|
+
- rubocop-rspec
|
4
4
|
|
5
5
|
AllCops:
|
6
6
|
TargetRubyVersion: 2.3
|
7
7
|
|
8
8
|
Metrics/BlockLength:
|
9
|
+
Enabled: false
|
9
10
|
Exclude:
|
10
11
|
- "Gemfile"
|
11
12
|
- "spec/**/*"
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
Layout/LineLength:
|
15
|
+
Max: 160
|
15
16
|
|
16
17
|
Style/StringLiterals:
|
17
18
|
EnforcedStyle: double_quotes
|
@@ -44,3 +45,23 @@ Style/TrailingCommaInHashLiteral:
|
|
44
45
|
Enabled: true
|
45
46
|
EnforcedStyleForMultiline: consistent_comma
|
46
47
|
|
48
|
+
Style/HashEachMethods:
|
49
|
+
Enabled: true
|
50
|
+
|
51
|
+
Style/HashTransformKeys:
|
52
|
+
Enabled: true
|
53
|
+
|
54
|
+
Style/HashTransformValues:
|
55
|
+
Enabled: true
|
56
|
+
|
57
|
+
RSpec/ExampleLength:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Style/Documentation:
|
61
|
+
Enabled: false
|
62
|
+
|
63
|
+
Metrics/MethodLength:
|
64
|
+
Max: 15
|
65
|
+
|
66
|
+
Metrics/AbcSize:
|
67
|
+
Max: 17
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## Unreleased
|
9
|
+
|
10
|
+
## 0.8.0 - 2021-05-12
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- `sidekiq_running_job_runtime` metric that tracks maximum runtime of currently running jobs. It may be useful for detection of hung jobs. See [#17](https://github.com/yabeda-rb/yabeda-sidekiq/pull/17). [@dsalahutdinov], [@Envek]
|
15
|
+
|
16
|
+
- Setting `collect_cluster_metrics` allowing to force enable or disable collection of global (whole Sidekiq installaction-wide) metrics. See [#20](https://github.com/yabeda-rb/yabeda-sidekiq/pull/20). [@mrexox]
|
17
|
+
|
18
|
+
By default all sidekiq worker processes (servers) collects global metrics about whole Sidekiq installation.
|
19
|
+
Client processes (everything else that is not Sidekiq worker) by default doesn't.
|
20
|
+
|
21
|
+
With this config you can override this behavior:
|
22
|
+
- force disable if you don't want multiple Sidekiq workers to report the same numbers (that causes excess load to both Redis and monitoring)
|
23
|
+
- force enable if you want non-Sidekiq process to collect them (like dedicated metric exporter process)
|
24
|
+
|
25
|
+
## 0.7.0 - 2020-07-15
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- Tags from `yabeda_tags` method are applied to all metrics collected inside a job, not only sidekiq-specific. See [#14](https://github.com/yabeda-rb/yabeda-sidekiq/issues/14). @Envek
|
30
|
+
|
31
|
+
## 0.6.0 - 2020-07-15
|
32
|
+
|
33
|
+
### Added
|
34
|
+
|
35
|
+
- Ability to override or add tags for every job via `yabeda_tags` method. @Envek
|
36
|
+
|
37
|
+
## 0.5.0 - 2020-02-20
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- New `sidekiq_job_latency` histogram to track latency statistics of different job classes. [#9](https://github.com/yabeda-rb/yabeda-sidekiq/pull/9) by [@asusikov]
|
42
|
+
|
43
|
+
### Changed
|
44
|
+
|
45
|
+
- **BREAKING CHANGE!** Renamed `sidekiq_jobs_latency` gauge to `sidekiq_queue_latency` to better describe its purpose and differentiate with the new histogram. [#9](https://github.com/yabeda-rb/yabeda-sidekiq/pull/9) by [@asusikov]
|
46
|
+
|
47
|
+
## 0.2.0 - 2020-01-14
|
48
|
+
|
49
|
+
### Changed
|
50
|
+
|
51
|
+
- Added `tags` option to metric declarations for compatibility with yabeda and yabeda-prometheus 0.2. @Envek
|
8
52
|
|
9
53
|
## 0.1.4 - 2019-10-07
|
10
54
|
|
@@ -34,4 +78,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
34
78
|
|
35
79
|
- Initial release of evil-metrics-sidekiq gem. @Envek
|
36
80
|
|
81
|
+
[@Envek]: https://github.com/Envek "Andrey Novikov"
|
37
82
|
[@dsalahutdinov]: https://github.com/dsalahutdinov "Salahutdinov Dmitry"
|
83
|
+
[@asusikov]: https://github.com/asusikov "Alexander Susikov"
|
84
|
+
[@mrexox]: https://github.com/mrexox "Valentine Kiselev"
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Built-in metrics for [Sidekiq] monitoring out of the box! Part of the [yabeda] suite.
|
4
4
|
|
5
|
+
Sample Grafana dashboard ID: [11667](https://grafana.com/grafana/dashboards/11667)
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
```ruby
|
@@ -14,6 +16,14 @@ And then execute:
|
|
14
16
|
|
15
17
|
$ bundle
|
16
18
|
|
19
|
+
If you're not on Rails then configure Yabeda after your application was initialized:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
Yabeda.configure!
|
23
|
+
```
|
24
|
+
|
25
|
+
_If you're using Ruby on Rails then Yabeda will configure itself automatically!_
|
26
|
+
|
17
27
|
**And that is it!** Sidekiq metrics are being collected!
|
18
28
|
|
19
29
|
Additionally, depending on your adapter, you may want to setup metrics export. E.g. for [yabeda-prometheus]:
|
@@ -27,17 +37,61 @@ end
|
|
27
37
|
|
28
38
|
## Metrics
|
29
39
|
|
40
|
+
### Local per-process metrics
|
41
|
+
|
42
|
+
Metrics representing state of current Sidekiq worker process and stats of executed or executing jobs:
|
43
|
+
|
30
44
|
- Total number of executed jobs: `sidekiq_jobs_executed_total` - (segmented by queue and class name)
|
31
45
|
- Number of jobs have been finished successfully: `sidekiq_jobs_success_total` (segmented by queue and class name)
|
32
46
|
- Number of jobs have been failed: `sidekiq_jobs_failed_total` (segmented by queue and class name)
|
33
47
|
- Time of job run: `sidekiq_job_runtime` (seconds per job execution, segmented by queue and class name)
|
34
|
-
- Time of the
|
48
|
+
- Time of the job latency `sidekiq_job_latency` (the difference in seconds since the enqueuing until running job)
|
49
|
+
- Maximum runtime of currently executing jobs: `sidekiq_running_job_runtime` (useful for detection of hung jobs, segmented by queue and class name)
|
50
|
+
|
51
|
+
### Global cluster-wide metrics
|
52
|
+
|
53
|
+
Metrics representing state of the whole Sidekiq installation (queues, processes, etc):
|
54
|
+
|
35
55
|
- Number of jobs in queues: `sidekiq_jobs_waiting_count` (segmented by queue)
|
56
|
+
- Time of the queue latency `sidekiq_queue_latency` (the difference in seconds since the oldest job in the queue was enqueued)
|
36
57
|
- Number of scheduled jobs:`sidekiq_jobs_scheduled_count`
|
37
58
|
- Number of jobs in retry set: `sidekiq_jobs_retry_count`
|
38
59
|
- Number of jobs in dead set (“morgue”): `sidekiq_jobs_dead_count`
|
39
|
-
- Active
|
40
|
-
- Active
|
60
|
+
- Active processes count: `sidekiq_active_processes`
|
61
|
+
- Active servers count: `sidekiq_active_workers_count`
|
62
|
+
|
63
|
+
By default all sidekiq worker processes (servers) collects global metrics about whole Sidekiq installation. This can be overridden by setting `collect_cluster_metrics` config key to `true` for non-Sidekiq processes or to `false` for Sidekiq processes (e.g. by setting `YABEDA_SIDEKIQ_COLLECT_CLUSTER_METRICS` env variable to `no`, see other methods in [anyway_config] docs).
|
64
|
+
|
65
|
+
## Custom tags
|
66
|
+
|
67
|
+
You can add additional tags to these metrics by declaring `yabeda_tags` method in your worker.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# This block is optional but some adapters (like Prometheus) requires that all tags should be declared in advance
|
71
|
+
Yabeda.configure do
|
72
|
+
default_tag :importance, nil
|
73
|
+
end
|
74
|
+
|
75
|
+
class MyWorker
|
76
|
+
include Sidekiq::Worker
|
77
|
+
|
78
|
+
def yabeda_tags(*params) # This method will be called first, before +perform+
|
79
|
+
{ importance: extract_importance(params) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def perform(*params)
|
83
|
+
# Your logic here
|
84
|
+
end
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
## Configuration
|
89
|
+
|
90
|
+
Configuration is handled by [anyway_config] gem. With it you can load settings from environment variables (upcased and prefixed with `YABEDA_SIDEKIQ_`), YAML files, and other sources. See [anyway_config] docs for details.
|
91
|
+
|
92
|
+
Config key | Type | Default | Description |
|
93
|
+
------------------------- | -------- | ------------------------------------------------------- | ----------- |
|
94
|
+
`collect_cluster_metrics` | boolean | Enabled in Sidekiq worker processes, disabled otherwise | Defines whether this Ruby process should collect and expose metrics representing state of the whole Sidekiq installation (queues, processes, etc). |
|
41
95
|
|
42
96
|
# Roadmap (TODO or Help wanted)
|
43
97
|
|
@@ -57,6 +111,38 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
57
111
|
|
58
112
|
Bug reports and pull requests are welcome on GitHub at https://github.com/yabeda-rb/yabeda-sidekiq.
|
59
113
|
|
114
|
+
### Releasing
|
115
|
+
|
116
|
+
1. Bump version number in `lib/yabeda/sidekiq/version.rb`
|
117
|
+
|
118
|
+
In case of pre-releases keep in mind [rubygems/rubygems#3086](https://github.com/rubygems/rubygems/issues/3086) and check version with command like `Gem::Version.new(Yabeda::Sidekiq::VERSION).to_s`
|
119
|
+
|
120
|
+
2. Fill `CHANGELOG.md` with missing changes, add header with version and date.
|
121
|
+
|
122
|
+
3. Make a commit:
|
123
|
+
|
124
|
+
```sh
|
125
|
+
git add lib/yabeda/sidekiq/version.rb CHANGELOG.md
|
126
|
+
version=$(ruby -r ./lib/yabeda/sidekiq/version.rb -e "puts Gem::Version.new(Yabeda::Sidekiq::VERSION)")
|
127
|
+
git commit --message="${version}: " --edit
|
128
|
+
```
|
129
|
+
|
130
|
+
4. Create annotated tag:
|
131
|
+
|
132
|
+
```sh
|
133
|
+
git tag v${version} --annotate --message="${version}: " --edit --sign
|
134
|
+
```
|
135
|
+
|
136
|
+
5. Fill version name into subject line and (optionally) some description (list of changes will be taken from changelog and appended automatically)
|
137
|
+
|
138
|
+
6. Push it:
|
139
|
+
|
140
|
+
```sh
|
141
|
+
git push --follow-tags
|
142
|
+
```
|
143
|
+
|
144
|
+
7. GitHub Actions will create a new release, build and push gem into RubyGems! You're done!
|
145
|
+
|
60
146
|
## License
|
61
147
|
|
62
148
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -64,3 +150,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
64
150
|
[Sidekiq]: https://github.com/mperham/sidekiq/ "Simple, efficient background processing for Ruby"
|
65
151
|
[yabeda]: https://github.com/yabeda-rb/yabeda
|
66
152
|
[yabeda-prometheus]: https://github.com/yabeda-rb/yabeda-prometheus
|
153
|
+
[anyway_config]: https://github.com/palkan/anyway_config "Configuration library for Ruby gems and applications"
|
data/Rakefile
CHANGED
data/lib/yabeda/sidekiq.rb
CHANGED
@@ -7,36 +7,57 @@ require "yabeda"
|
|
7
7
|
require "yabeda/sidekiq/version"
|
8
8
|
require "yabeda/sidekiq/client_middleware"
|
9
9
|
require "yabeda/sidekiq/server_middleware"
|
10
|
+
require "yabeda/sidekiq/config"
|
10
11
|
|
11
12
|
module Yabeda
|
12
13
|
module Sidekiq
|
13
14
|
LONG_RUNNING_JOB_RUNTIME_BUCKETS = [
|
14
15
|
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, # standard (from Prometheus)
|
15
|
-
30, 60, 120, 300, 1800, 3600, 21_600 # Sidekiq tasks may be very long-running
|
16
|
+
30, 60, 120, 300, 1800, 3600, 21_600, # Sidekiq tasks may be very long-running
|
16
17
|
].freeze
|
17
18
|
|
18
19
|
Yabeda.configure do
|
20
|
+
config = Config.new
|
21
|
+
|
19
22
|
group :sidekiq
|
20
23
|
|
21
|
-
counter :jobs_enqueued_total, comment: "A counter of the total number of jobs sidekiq enqueued."
|
24
|
+
counter :jobs_enqueued_total, tags: %i[queue worker], comment: "A counter of the total number of jobs sidekiq enqueued."
|
25
|
+
|
26
|
+
if ::Sidekiq.server?
|
27
|
+
counter :jobs_executed_total, tags: %i[queue worker], comment: "A counter of the total number of jobs sidekiq executed."
|
28
|
+
counter :jobs_success_total, tags: %i[queue worker], comment: "A counter of the total number of jobs successfully processed by sidekiq."
|
29
|
+
counter :jobs_failed_total, tags: %i[queue worker], comment: "A counter of the total number of jobs failed in sidekiq."
|
22
30
|
|
23
|
-
|
31
|
+
gauge :running_job_runtime, tags: %i[queue worker], aggregation: :max, unit: :seconds,
|
32
|
+
comment: "How long currently running jobs are running (useful for detection of hung jobs)"
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
gauge :jobs_latency, comment: "The job latency, the difference in seconds since the oldest job in the queue was enqueued"
|
34
|
+
histogram :job_latency, comment: "The job latency, the difference in seconds between enqueued and running time",
|
35
|
+
unit: :seconds, per: :job,
|
36
|
+
tags: %i[queue worker],
|
37
|
+
buckets: LONG_RUNNING_JOB_RUNTIME_BUCKETS
|
38
|
+
histogram :job_runtime, comment: "A histogram of the job execution time.",
|
39
|
+
unit: :seconds, per: :job,
|
40
|
+
tags: %i[queue worker],
|
41
|
+
buckets: LONG_RUNNING_JOB_RUNTIME_BUCKETS
|
42
|
+
end
|
35
43
|
|
36
|
-
|
37
|
-
|
44
|
+
# Metrics not specific for current Sidekiq process, but representing state of the whole Sidekiq installation (queues, processes, etc)
|
45
|
+
# You can opt-out from collecting these by setting YABEDA_SIDEKIQ_COLLECT_CLUSTER_METRICS to falsy value (+no+ or +false+)
|
46
|
+
if config.collect_cluster_metrics # defaults to +::Sidekiq.server?+
|
47
|
+
gauge :jobs_waiting_count, tags: %i[queue], comment: "The number of jobs waiting to process in sidekiq."
|
48
|
+
gauge :active_workers_count, tags: [], comment: "The number of currently running machines with sidekiq workers."
|
49
|
+
gauge :jobs_scheduled_count, tags: [], comment: "The number of jobs scheduled for later execution."
|
50
|
+
gauge :jobs_retry_count, tags: [], comment: "The number of failed jobs waiting to be retried"
|
51
|
+
gauge :jobs_dead_count, tags: [], comment: "The number of jobs exceeded their retry count."
|
52
|
+
gauge :active_processes, tags: [], comment: "The number of active Sidekiq worker processes."
|
53
|
+
gauge :queue_latency, tags: %i[queue], comment: "The queue latency, the difference in seconds since the oldest job in the queue was enqueued"
|
54
|
+
end
|
38
55
|
|
39
56
|
collect do
|
57
|
+
Yabeda::Sidekiq.track_max_job_runtime if ::Sidekiq.server?
|
58
|
+
|
59
|
+
next unless config.collect_cluster_metrics
|
60
|
+
|
40
61
|
stats = ::Sidekiq::Stats.new
|
41
62
|
|
42
63
|
stats.queues.each do |k, v|
|
@@ -49,7 +70,7 @@ module Yabeda
|
|
49
70
|
sidekiq_jobs_retry_count.set({}, stats.retry_size)
|
50
71
|
|
51
72
|
::Sidekiq::Queue.all.each do |queue|
|
52
|
-
|
73
|
+
sidekiq_queue_latency.set({ queue: queue.name }, queue.latency)
|
53
74
|
end
|
54
75
|
|
55
76
|
# That is quite slow if your retry set is large
|
@@ -86,10 +107,34 @@ module Yabeda
|
|
86
107
|
|
87
108
|
def worker_class(worker, job)
|
88
109
|
if defined?(ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper)
|
89
|
-
|
110
|
+
if worker.is_a?(ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper) || worker == ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper
|
111
|
+
return job["wrapped"].to_s
|
112
|
+
end
|
113
|
+
end
|
114
|
+
(worker.is_a?(String) || worker.is_a?(Class) ? worker : worker.class).to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
def custom_tags(worker, job)
|
118
|
+
return {} unless worker.respond_to?(:yabeda_tags)
|
119
|
+
|
120
|
+
worker.method(:yabeda_tags).arity.zero? ? worker.yabeda_tags : worker.yabeda_tags(*job["args"])
|
121
|
+
end
|
122
|
+
|
123
|
+
# Hash of hashes containing all currently running jobs' start timestamps
|
124
|
+
# to calculate maximum durations of currently running not yet completed jobs
|
125
|
+
# { { queue: "default", worker: "SomeJob" } => { "jid1" => 100500, "jid2" => 424242 } }
|
126
|
+
attr_accessor :jobs_started_at
|
127
|
+
|
128
|
+
def track_max_job_runtime
|
129
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
130
|
+
::Yabeda::Sidekiq.jobs_started_at.each do |labels, jobs|
|
131
|
+
oldest_job_started_at = jobs.values.min
|
132
|
+
oldest_job_duration = oldest_job_started_at ? (now - oldest_job_started_at).round(3) : 0
|
133
|
+
Yabeda.sidekiq.running_job_runtime.set(labels, oldest_job_duration)
|
90
134
|
end
|
91
|
-
(worker.is_a?(String) ? worker : worker.class).to_s
|
92
135
|
end
|
93
136
|
end
|
137
|
+
|
138
|
+
self.jobs_started_at = Concurrent::Hash.new { |hash, key| hash[key] = Concurrent::Hash.new }
|
94
139
|
end
|
95
140
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "anyway"
|
4
|
+
|
5
|
+
module Yabeda
|
6
|
+
module Sidekiq
|
7
|
+
class Config < ::Anyway::Config
|
8
|
+
config_name :yabeda_sidekiq
|
9
|
+
|
10
|
+
# By default all sidekiq worker processes (servers) collects global metrics about whole Sidekiq installation.
|
11
|
+
# Client processes (everything else that is not Sidekiq worker) by default doesn't.
|
12
|
+
# With this config you can override this behavior:
|
13
|
+
# - force disable if you don't want multiple Sidekiq workers to report the same numbers (that causes excess load to both Redis and monitoring)
|
14
|
+
# - force enable if you want non-Sidekiq process to collect them (like dedicated metric exporter process)
|
15
|
+
attr_config collect_cluster_metrics: ::Sidekiq.server?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,11 +4,18 @@ module Yabeda
|
|
4
4
|
module Sidekiq
|
5
5
|
# Sidekiq worker middleware
|
6
6
|
class ServerMiddleware
|
7
|
+
# rubocop: disable Metrics/AbcSize, Metrics/MethodLength:
|
7
8
|
def call(worker, job, queue)
|
8
|
-
|
9
|
-
|
9
|
+
custom_tags = Yabeda::Sidekiq.custom_tags(worker, job).to_h
|
10
|
+
labels = Yabeda::Sidekiq.labelize(worker, job, queue).merge(custom_tags)
|
11
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
10
12
|
begin
|
11
|
-
|
13
|
+
job_instance = ::Sidekiq::Job.new(job)
|
14
|
+
Yabeda.sidekiq_job_latency.measure(labels, job_instance.latency)
|
15
|
+
Yabeda::Sidekiq.jobs_started_at[labels][job["jid"]] = start
|
16
|
+
Yabeda.with_tags(**custom_tags) do
|
17
|
+
yield
|
18
|
+
end
|
12
19
|
Yabeda.sidekiq_jobs_success_total.increment(labels)
|
13
20
|
rescue Exception # rubocop: disable Lint/RescueException
|
14
21
|
Yabeda.sidekiq_jobs_failed_total.increment(labels)
|
@@ -16,13 +23,15 @@ module Yabeda
|
|
16
23
|
ensure
|
17
24
|
Yabeda.sidekiq_job_runtime.measure(labels, elapsed(start))
|
18
25
|
Yabeda.sidekiq_jobs_executed_total.increment(labels)
|
26
|
+
Yabeda::Sidekiq.jobs_started_at[labels].delete(job["jid"])
|
19
27
|
end
|
20
28
|
end
|
29
|
+
# rubocop: enable Metrics/AbcSize, Metrics/MethodLength:
|
21
30
|
|
22
31
|
private
|
23
32
|
|
24
33
|
def elapsed(start)
|
25
|
-
(
|
34
|
+
(Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).round(3)
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
data/yabeda-sidekiq.gemspec
CHANGED
@@ -22,10 +22,12 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
|
25
|
-
spec.add_dependency "
|
25
|
+
spec.add_dependency "anyway_config", ">= 1.3", "< 3"
|
26
26
|
spec.add_dependency "sidekiq"
|
27
|
+
spec.add_dependency "yabeda", "~> 0.6"
|
27
28
|
|
28
|
-
spec.add_development_dependency "
|
29
|
-
spec.add_development_dependency "
|
29
|
+
spec.add_development_dependency "activejob", ">= 6.0"
|
30
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
31
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
30
32
|
spec.add_development_dependency "rspec", "~> 3.0"
|
31
33
|
end
|
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yabeda-sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Novikov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: anyway_config
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.3'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
29
|
+
version: '1.3'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: sidekiq
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,34 +44,62 @@ dependencies:
|
|
38
44
|
- - ">="
|
39
45
|
- !ruby/object:Gem::Version
|
40
46
|
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: yabeda
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.6'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.6'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: activejob
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '6.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '6.0'
|
41
75
|
- !ruby/object:Gem::Dependency
|
42
76
|
name: bundler
|
43
77
|
requirement: !ruby/object:Gem::Requirement
|
44
78
|
requirements:
|
45
79
|
- - "~>"
|
46
80
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
81
|
+
version: '2.0'
|
48
82
|
type: :development
|
49
83
|
prerelease: false
|
50
84
|
version_requirements: !ruby/object:Gem::Requirement
|
51
85
|
requirements:
|
52
86
|
- - "~>"
|
53
87
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
88
|
+
version: '2.0'
|
55
89
|
- !ruby/object:Gem::Dependency
|
56
90
|
name: rake
|
57
91
|
requirement: !ruby/object:Gem::Requirement
|
58
92
|
requirements:
|
59
93
|
- - "~>"
|
60
94
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
95
|
+
version: '13.0'
|
62
96
|
type: :development
|
63
97
|
prerelease: false
|
64
98
|
version_requirements: !ruby/object:Gem::Requirement
|
65
99
|
requirements:
|
66
100
|
- - "~>"
|
67
101
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
102
|
+
version: '13.0'
|
69
103
|
- !ruby/object:Gem::Dependency
|
70
104
|
name: rspec
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -88,10 +122,11 @@ executables: []
|
|
88
122
|
extensions: []
|
89
123
|
extra_rdoc_files: []
|
90
124
|
files:
|
125
|
+
- ".github/workflows/build-release.yml"
|
126
|
+
- ".github/workflows/test.yml"
|
91
127
|
- ".gitignore"
|
92
128
|
- ".rspec"
|
93
129
|
- ".rubocop.yml"
|
94
|
-
- ".travis.yml"
|
95
130
|
- CHANGELOG.md
|
96
131
|
- Gemfile
|
97
132
|
- LICENSE.txt
|
@@ -101,6 +136,7 @@ files:
|
|
101
136
|
- bin/setup
|
102
137
|
- lib/yabeda/sidekiq.rb
|
103
138
|
- lib/yabeda/sidekiq/client_middleware.rb
|
139
|
+
- lib/yabeda/sidekiq/config.rb
|
104
140
|
- lib/yabeda/sidekiq/server_middleware.rb
|
105
141
|
- lib/yabeda/sidekiq/version.rb
|
106
142
|
- yabeda-sidekiq.gemspec
|
@@ -123,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
123
159
|
- !ruby/object:Gem::Version
|
124
160
|
version: '0'
|
125
161
|
requirements: []
|
126
|
-
rubygems_version: 3.
|
162
|
+
rubygems_version: 3.1.6
|
127
163
|
signing_key:
|
128
164
|
specification_version: 4
|
129
165
|
summary: Extensible Prometheus exporter for monitoring your Sidekiq
|