workhorse 1.4.4 → 1.4.5

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: 02c3e3163a1b21b8a983c756e9be5e916b2cc7017401ab3484905c04fe56293f
4
- data.tar.gz: 52ffb9742bf24ea226e3aa3f7edf2f0a5deecdefa57310c3176a40bec00f227f
3
+ metadata.gz: ef9cd623d06cab42a5c5a849f9a5c334c0bb8f4dd517f2c84e5ba3c4df611b24
4
+ data.tar.gz: 9681900417bc660a347afeeaebf6cf57fa342268afc38c24b4e5ce11479ce1e3
5
5
  SHA512:
6
- metadata.gz: ce5cd0d30660a0bb9829c84957e76589d5e65e9c47795c7ff414101df2b57f8661fbf01cd4b73bb4a69b7901f4fc43796a3a43e6f400c31b5c1a5b6b1eff8e56
7
- data.tar.gz: 3594464e0fd00d036c9fe163daeea5a17d78d2fcd79095be05dac95753fbce43530812881529052af28917240920f70f706b708f7902d38636caa4e5c6995d3a
6
+ metadata.gz: 86a5b9f9db82efbd890dc77fa763dcc1052027df45d922358428e721bfe3e900670e28b1e55af06e04972fef7c6408fe8a445239443f0707063281d4baf344fe
7
+ data.tar.gz: 74f47b979b3589b5530947638c7ec7a6acbb9f85599c88bd9eccaf25fcecf5a92addecb58fa9357bc07eb840bf16b31e5a7fe7fe2f9a6e11fa697b31d9aaf526
data/.releaser_config CHANGED
@@ -1,3 +1,3 @@
1
1
  version_file: VERSION
2
- always_from_master: false
2
+ always_from_master: true
3
3
  gem_style: github
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Workhorse Changelog
2
2
 
3
+ ## 1.4.5 - 2026-05-09
4
+
5
+ * Close the lockfile after releasing the lock in the ShellHandler.
6
+
7
+ Sitrox reference: #120574.
8
+
9
+ * Prevent YJIT from being enabled when `RUBY_YJIT_ENABLE=0` is set. This allows
10
+ running workhorse commands in systemd services that set
11
+ `MemoryDenyWriteExecute=yes`.
12
+
13
+ Sitrox reference: #120574.
14
+
3
15
  ## 1.4.4 - 2026-04-28
4
16
 
5
17
  * Make debug logging (enabled if `config.debug_log_path` is set) more verbose.
data/README.md CHANGED
@@ -529,6 +529,17 @@ ActiveSupport.on_load :workhorse_db_job do
529
529
  end
530
530
  ```
531
531
 
532
+ ## Running in systemd services
533
+
534
+ When running workhorse commands inside a systemd service that sets
535
+ `MemoryDenyWriteExecute=yes`, Ruby's YJIT cannot allocate executable memory and
536
+ will crash. To prevent this, set `RUBY_YJIT_ENABLE=0` before invoking the
537
+ workhorse command:
538
+
539
+ ```bash
540
+ RUBY_YJIT_ENABLE=0 ./bin/workhorse restart-logging
541
+ ```
542
+
532
543
  ## Debug logging
533
544
 
534
545
  Workhorse includes an optional debug log for diagnosing issues with signal
data/RUBY_VERSION CHANGED
@@ -1 +1 @@
1
- ruby-3.2.1-p31
1
+ ruby-3.3.5
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.4
1
+ 1.4.5
@@ -88,6 +88,7 @@ module Workhorse
88
88
  if lockfile
89
89
  Workhorse.debug_log("ShellHandler: releasing lock for #{ARGV.first}")
90
90
  lockfile.flock(File::LOCK_UN)
91
+ lockfile.close
91
92
  end
92
93
  Workhorse.debug_log("ShellHandler: exiting with status #{status}")
93
94
  exit! status
@@ -145,7 +146,7 @@ module Workhorse
145
146
 
146
147
  def self.acquire_lock(lockfile_path, flags)
147
148
  if Workhorse.lock_shell_commands
148
- lockfile = File.open(lockfile_path, 'a')
149
+ lockfile = File.open(lockfile_path, 'a') # rubocop:disable Style/FileOpen
149
150
  result = lockfile.flock(flags)
150
151
 
151
152
  if result == false
@@ -310,7 +310,7 @@ module Workhorse
310
310
  @lockfile&.close
311
311
  # Reopen pipes to prevent #107576
312
312
  $stdin.reopen File.open(File::NULL, 'r')
313
- null_out = File.open File::NULL, 'w'
313
+ null_out = File.open(File::NULL, 'w') # rubocop:disable Style/FileOpen
314
314
  $stdout.reopen null_out
315
315
  $stderr.reopen null_out
316
316
 
data/lib/workhorse.rb CHANGED
@@ -8,6 +8,16 @@ require 'workhorse/enqueuer'
8
8
  require 'workhorse/scoped_env'
9
9
  require 'workhorse/active_job_extension'
10
10
 
11
+ # Prevent YJIT from being enabled when RUBY_YJIT_ENABLE is explicitly set to 0.
12
+ # systemd's logrotate.service typically sets MemoryDenyWriteExecute=yes, which
13
+ # prevents mprotect(PROT_EXEC). Rails unconditionally calls
14
+ # RubyVM::YJIT.enable on boot, which triggers a fatal Ruby [BUG] in that
15
+ # environment. Set RUBY_YJIT_ENABLE=0 in the logrotate postrotate script
16
+ # to prevent this.
17
+ if ENV['RUBY_YJIT_ENABLE'] == '0' && defined?(RubyVM::YJIT) && !RubyVM::YJIT.enabled?
18
+ RubyVM::YJIT.define_singleton_method(:enable) { |**| nil }
19
+ end
20
+
11
21
  # Main Gem module.
12
22
  module Workhorse
13
23
  # Check if the available Arel version is greater or equal than 7.0.0
@@ -0,0 +1,37 @@
1
+ require 'English'
2
+ require 'test_helper'
3
+ require 'bundler'
4
+
5
+ class Workhorse::YjitTest < ActiveSupport::TestCase
6
+ YJIT_CHECK_SCRIPT = <<~RUBY.freeze
7
+ require 'bundler/setup'
8
+ require 'workhorse'
9
+ RubyVM::YJIT.enable
10
+ print RubyVM::YJIT.enabled?
11
+ RUBY
12
+
13
+ def test_yjit_not_enabled_when_ruby_yjit_enable_is_zero
14
+ skip 'RubyVM::YJIT.enable not available' unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enable)
15
+
16
+ # Sanity check: YJIT can actually be enabled in this environment
17
+ without_env = run_ruby_script(YJIT_CHECK_SCRIPT, 'RUBY_YJIT_ENABLE' => nil)
18
+ skip 'YJIT cannot be enabled in this environment' unless without_env == 'true'
19
+
20
+ # With RUBY_YJIT_ENABLE=0, RubyVM::YJIT.enable should be a no-op
21
+ with_env = run_ruby_script(YJIT_CHECK_SCRIPT, 'RUBY_YJIT_ENABLE' => '0')
22
+ assert_equal 'false', with_env, 'YJIT should not be enabled when RUBY_YJIT_ENABLE=0'
23
+ end
24
+
25
+ private
26
+
27
+ def run_ruby_script(script, env = {})
28
+ output = nil
29
+ Bundler.with_unbundled_env do
30
+ IO.popen(env, %w[bundle exec ruby -e] + [script], chdir: Rails.root.to_s, err: %i[child out]) do |io|
31
+ output = io.read.strip
32
+ end
33
+ end
34
+ assert $CHILD_STATUS.success?, "Ruby subprocess failed (exit #{$CHILD_STATUS.exitstatus}): #{output}"
35
+ output
36
+ end
37
+ end
data/workhorse.gemspec CHANGED
@@ -1,24 +1,24 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: workhorse 1.4.4 ruby lib
2
+ # stub: workhorse 1.4.5 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "workhorse".freeze
6
- s.version = "1.4.4"
6
+ s.version = "1.4.5".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2026-04-28"
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/daemon_test.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]
11
+ s.date = "2026-05-09"
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/daemon_test.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, "test/workhorse/yjit_test.rb".freeze, "workhorse.gemspec".freeze]
13
13
  s.homepage = "https://github.com/sitrox/workhorse".freeze
14
14
  s.licenses = ["MIT".freeze]
15
- s.rubygems_version = "3.4.6".freeze
15
+ s.rubygems_version = "3.5.18".freeze
16
16
  s.summary = "Multi-threaded job backend with database queuing for ruby.".freeze
17
- 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/daemon_test.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]
17
+ 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/daemon_test.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, "test/workhorse/yjit_test.rb".freeze]
18
18
 
19
19
  s.specification_version = 4
20
20
 
21
- s.add_runtime_dependency(%q<activesupport>.freeze, [">= 7.0.0"])
22
- s.add_runtime_dependency(%q<activerecord>.freeze, [">= 7.0.0"])
23
- s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0"])
21
+ s.add_runtime_dependency(%q<activesupport>.freeze, [">= 7.0.0".freeze])
22
+ s.add_runtime_dependency(%q<activerecord>.freeze, [">= 7.0.0".freeze])
23
+ s.add_runtime_dependency(%q<concurrent-ruby>.freeze, [">= 0".freeze])
24
24
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workhorse
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-04-28 00:00:00.000000000 Z
10
+ date: 2026-05-09 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -99,6 +99,7 @@ files:
99
99
  - test/workhorse/poller_test.rb
100
100
  - test/workhorse/pool_test.rb
101
101
  - test/workhorse/worker_test.rb
102
+ - test/workhorse/yjit_test.rb
102
103
  - workhorse.gemspec
103
104
  homepage: https://github.com/sitrox/workhorse
104
105
  licenses:
@@ -133,3 +134,4 @@ test_files:
133
134
  - test/workhorse/poller_test.rb
134
135
  - test/workhorse/pool_test.rb
135
136
  - test/workhorse/worker_test.rb
137
+ - test/workhorse/yjit_test.rb