workhorse 1.2.16 → 1.2.17.rc0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c50e38fd05785d30e0dfa783d732f46df2be9b980ac0a54dca1a2d91264ff9d
4
- data.tar.gz: a4b282a25d39429da15c5380a41a1786b54b24b2b8afb4961786881380eecacf
3
+ metadata.gz: 25908f294cd9623ebde44ec8bba5181ee54965703f4fb93df18876b216718eb8
4
+ data.tar.gz: 568e620571a9ded165fee1fc4420efbb6810f073edd4365c6c8efbe7c3676052
5
5
  SHA512:
6
- metadata.gz: f8fefeb28bb6651e93163e5d9b8744994f681064bf55168b73d8ca5e9c72aee9e3f7642d03a86eb496ebd81bf15e724757cb4f0a6790dcb87e3ae5f3ef09344d
7
- data.tar.gz: '090f112b83a2a69015e0244345d30616af8701bf99f2a6814238006efa2cca49850dfe024b26d1359b2863d01bf2c84d0bbf84a7122419f540969ba7f8d66dea'
6
+ metadata.gz: 83b6ac441e3762f251e35f04dd213044d6fb904a005155235546391cdecd4f9c0c1db24be7c30371da4704b27e6f18aa6ce0b448b6c6c1dbc8c77eeb81faa9e3
7
+ data.tar.gz: 9c2940a6bfb7cd0be49170d81af2378f27395dbf597f6d8fa2c777bdc812b26d06cc849454ba5925fcf5f26b7724779b3d6e941bc6c9237d6dc251b7d071188f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Workhorse Changelog
2
2
 
3
+ ## 1.2.17.rc0 - 2024-02-05
4
+
5
+ * Add option `config.max_worker_memory_mb` for automatic restart of workers
6
+ exceeding the specified memory threshold using the `watch` command. Default is
7
+ `0`, deactivating this feature. See [memory
8
+ handling](README.md#memory-handling) for more information.
9
+
10
+ Sitrox reference: #121312.
11
+
3
12
  ## 1.2.16 - 2023-09-18
4
13
 
5
14
  * Add support for `--skip-initializer` flag to install generator.
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017 - 2023 Sitrox
3
+ Copyright (c) 2017 - 2024 Sitrox
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -464,6 +464,29 @@ jobs database on a regular interval. Workhorse provides the job
464
464
  `Workhorse::Jobs::CleanupSucceededJobs` for this purpose that cleans up all
465
465
  succeeded jobs. You can run this using your scheduler in a specific interval.
466
466
 
467
+ ## Memory handling
468
+
469
+ When dealing with jobs that may exhibit a large memory footprint, it's important
470
+ to note that Ruby might not release consumed memory back to the operating
471
+ system. Consequently, your job workers could accumulate a significant amount of
472
+ memory over time. To address this, Workhorse provides the
473
+ `config.max_worker_memory_mb` option.
474
+
475
+ If `config.max_worker_memory_mb` is set to a value above `0`, the `watch`
476
+ command will check the memory footprint (RSS / resident size) of all worker
477
+ processes. If any worker exceeds the specified footprint, Workhorse will
478
+ silently restart it to ensure proper memory release. This process does not
479
+ produce any output in the `watch` command.
480
+
481
+ Example configuration:
482
+
483
+ ```ruby
484
+ # config/initializers/workhorse.rb
485
+ Workhorse.setup do |config|
486
+ config.max_worker_memory_mb = 512 # Set the memory threshold to 512 megabytes
487
+ end
488
+ ```
489
+
467
490
  ## Load hooks
468
491
 
469
492
  Using the load hook `:workhorse_db_job`, you can inject custom code into the
@@ -540,4 +563,4 @@ Please consult the [FAQ](FAQ.md).
540
563
 
541
564
  ## Copyright
542
565
 
543
- Copyright © 2017 - 2023 Sitrox. See `LICENSE` for further details.
566
+ Copyright © 2017 - 2024 Sitrox. See `LICENSE` for further details.
data/RUBY_VERSION CHANGED
@@ -1 +1 @@
1
- ruby-2.7.1-p83
1
+ ruby-3.2.1-p31
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.16
1
+ 1.2.17.rc0
@@ -113,10 +113,14 @@ module Workhorse
113
113
  end
114
114
 
115
115
  if should_be_running && status(quiet: true) != 0
116
- return start(quiet: Workhorse.silence_watcher)
116
+ code = start(quiet: Workhorse.silence_watcher)
117
117
  else
118
- return 0
118
+ code = 0
119
119
  end
120
+
121
+ watch_memory! if should_be_running
122
+
123
+ return code
120
124
  end
121
125
 
122
126
  def restart
@@ -144,6 +148,30 @@ module Workhorse
144
148
 
145
149
  private
146
150
 
151
+ def watch_memory!
152
+ return if Workhorse.max_worker_memory_mb == 0
153
+
154
+ for_each_worker do |worker|
155
+ pid_file, pid = read_pid(worker)
156
+ next unless pid_file && pid
157
+
158
+ memory = memory_for(pid)
159
+ next unless memory
160
+
161
+ if memory > Workhorse.max_worker_memory_mb
162
+ stop_worker pid_file, pid
163
+ start_worker worker
164
+ end
165
+ end
166
+ end
167
+
168
+ # Returns the memory (RSS) in MB for the given process.
169
+ def memory_for(pid)
170
+ mem = `ps -p #{pid} -o rss=`&.strip
171
+ return nil if mem.blank?
172
+ return mem.to_i / 1024
173
+ end
174
+
147
175
  def for_each_worker(&block)
148
176
  @workers.each(&block)
149
177
  end
data/lib/workhorse.rb CHANGED
@@ -75,6 +75,12 @@ module Workhorse
75
75
  mattr_accessor :stale_detection_run_time_threshold
76
76
  self.stale_detection_run_time_threshold = 12 * 60
77
77
 
78
+ # Maximum memory for a worker in MB. If this memory limit (RSS / resident
79
+ # size) is reached for a worker process, the 'watch' command will restart said
80
+ # worker. Set this to 0 disable this feature.
81
+ mattr_accessor :max_worker_memory_mb
82
+ self.max_worker_memory_mb = 0
83
+
78
84
  def self.setup
79
85
  yield self
80
86
  end
data/workhorse.gemspec CHANGED
@@ -1,48 +1,31 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: workhorse 1.2.16 ruby lib
2
+ # stub: workhorse 1.2.17.rc0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "workhorse".freeze
6
- s.version = "1.2.16"
6
+ s.version = "1.2.17.rc0"
7
7
 
8
- s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
8
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2023-09-18"
11
+ s.date = "2024-02-05"
12
12
  s.files = [".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "CHANGELOG.md".freeze, "FAQ.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "RUBY_VERSION".freeze, "Rakefile".freeze, "VERSION".freeze, "bin/rubocop".freeze, "lib/active_job/queue_adapters/workhorse_adapter.rb".freeze, "lib/generators/workhorse/install_generator.rb".freeze, "lib/generators/workhorse/templates/bin/workhorse.rb".freeze, "lib/generators/workhorse/templates/config/initializers/workhorse.rb".freeze, "lib/generators/workhorse/templates/create_table_jobs.rb".freeze, "lib/workhorse.rb".freeze, "lib/workhorse/active_job_extension.rb".freeze, "lib/workhorse/daemon.rb".freeze, "lib/workhorse/daemon/shell_handler.rb".freeze, "lib/workhorse/db_job.rb".freeze, "lib/workhorse/enqueuer.rb".freeze, "lib/workhorse/jobs/cleanup_succeeded_jobs.rb".freeze, "lib/workhorse/jobs/detect_stale_jobs_job.rb".freeze, "lib/workhorse/jobs/run_active_job.rb".freeze, "lib/workhorse/jobs/run_rails_op.rb".freeze, "lib/workhorse/performer.rb".freeze, "lib/workhorse/poller.rb".freeze, "lib/workhorse/pool.rb".freeze, "lib/workhorse/scoped_env.rb".freeze, "lib/workhorse/worker.rb".freeze, "test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze, "workhorse.gemspec".freeze]
13
- s.rubygems_version = "3.1.2".freeze
13
+ s.rubygems_version = "3.4.6".freeze
14
14
  s.summary = "Multi-threaded job backend with database queuing for ruby.".freeze
15
15
  s.test_files = ["test/active_job/queue_adapters/workhorse_adapter_test.rb".freeze, "test/lib/db_schema.rb".freeze, "test/lib/jobs.rb".freeze, "test/lib/test_helper.rb".freeze, "test/workhorse/db_job_test.rb".freeze, "test/workhorse/enqueuer_test.rb".freeze, "test/workhorse/performer_test.rb".freeze, "test/workhorse/poller_test.rb".freeze, "test/workhorse/pool_test.rb".freeze, "test/workhorse/worker_test.rb".freeze]
16
16
 
17
- if s.respond_to? :specification_version then
18
- s.specification_version = 4
19
- end
17
+ s.specification_version = 4
20
18
 
21
- if s.respond_to? :add_runtime_dependency then
22
- s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
23
- s.add_development_dependency(%q<rake>.freeze, [">= 0"])
24
- s.add_development_dependency(%q<rubocop>.freeze, ["~> 1.28.0"])
25
- s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
26
- s.add_development_dependency(%q<mysql2>.freeze, [">= 0"])
27
- s.add_development_dependency(%q<colorize>.freeze, [">= 0"])
28
- s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
29
- s.add_development_dependency(%q<activejob>.freeze, [">= 0"])
30
- s.add_development_dependency(%q<pry>.freeze, [">= 0"])
31
- s.add_runtime_dependency(%q<activesupport>.freeze, [">= 0"])
32
- s.add_runtime_dependency(%q<activerecord>.freeze, [">= 0"])
33
- s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
34
- else
35
- s.add_dependency(%q<bundler>.freeze, [">= 0"])
36
- s.add_dependency(%q<rake>.freeze, [">= 0"])
37
- s.add_dependency(%q<rubocop>.freeze, ["~> 1.28.0"])
38
- s.add_dependency(%q<minitest>.freeze, [">= 0"])
39
- s.add_dependency(%q<mysql2>.freeze, [">= 0"])
40
- s.add_dependency(%q<colorize>.freeze, [">= 0"])
41
- s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
42
- s.add_dependency(%q<activejob>.freeze, [">= 0"])
43
- s.add_dependency(%q<pry>.freeze, [">= 0"])
44
- s.add_dependency(%q<activesupport>.freeze, [">= 0"])
45
- s.add_dependency(%q<activerecord>.freeze, [">= 0"])
46
- s.add_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
47
- end
19
+ s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
20
+ s.add_development_dependency(%q<rake>.freeze, [">= 0"])
21
+ s.add_development_dependency(%q<rubocop>.freeze, ["~> 1.28.0"])
22
+ s.add_development_dependency(%q<minitest>.freeze, [">= 0"])
23
+ s.add_development_dependency(%q<mysql2>.freeze, [">= 0"])
24
+ s.add_development_dependency(%q<colorize>.freeze, [">= 0"])
25
+ s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
26
+ s.add_development_dependency(%q<activejob>.freeze, [">= 0"])
27
+ s.add_development_dependency(%q<pry>.freeze, [">= 0"])
28
+ s.add_runtime_dependency(%q<activesupport>.freeze, [">= 0"])
29
+ s.add_runtime_dependency(%q<activerecord>.freeze, [">= 0"])
30
+ s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
48
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workhorse
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.16
4
+ version: 1.2.17.rc0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-18 00:00:00.000000000 Z
11
+ date: 2024-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -242,11 +242,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
242
242
  version: '0'
243
243
  required_rubygems_version: !ruby/object:Gem::Requirement
244
244
  requirements:
245
- - - ">="
245
+ - - ">"
246
246
  - !ruby/object:Gem::Version
247
- version: '0'
247
+ version: 1.3.1
248
248
  requirements: []
249
- rubygems_version: 3.4.6
249
+ rubygems_version: 3.4.10
250
250
  signing_key:
251
251
  specification_version: 4
252
252
  summary: Multi-threaded job backend with database queuing for ruby.