Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
timeout-minutes: 5

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup ruby
uses: ruby/setup-ruby@v1
Expand All @@ -28,21 +28,27 @@ jobs:
bundle exec stree check Gemfile $(git ls-files '*.rb') $(git ls-files '*.rake') $(git ls-files '*.thor')

test:
name: Ruby ${{ matrix.ruby }}, Sidekiq ${{ matrix.sidekiq }}, ${{ matrix.redis }}
runs-on: ubuntu-latest
timeout-minutes: 5

services:
redis:
image: redis
image: ${{ matrix.redis }}
ports:
- 6379:6379

strategy:
matrix:
ruby: ["3.1", "3.2", "3.3"]
ruby: ["3.0", "3.1", "3.2", "3.3"]
redis: ["redis", "valkey/valkey"]
sidekiq: ["6.5", "7.0", "7.1", "7.2", "7.3", "8.0", "8.1"]

env:
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/sidekiq-${{ matrix.sidekiq }}.gemfile

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup ruby
uses: ruby/setup-ruby@v1
Expand All @@ -59,7 +65,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Release Gem
uses: discourse/publish-rubygems-action@v3
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# 0.19.0 - 2025-12-04

- Fix race condition in `MiniScheduler::Manager`

# 0.18.0 - 2024-12-20

- Add support for Sidekiq 7+
- Remove support for Sidekiq < 6.5
- Update minimum Ruby version to 3.0

# 0.17.0 - 2024-08-06

- Add `MiniScheduler::Manager.discover_running_scheduled_jobs` API to allow running scheduled jobs to easily be discovered on the
Expand Down
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-6.5.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 6.5.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-7.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 7.0.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-7.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 7.1.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-7.2.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 7.2.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-7.3.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 7.3.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-8.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 8.0.0"
6 changes: 6 additions & 0 deletions gemfiles/sidekiq-8.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
source "https://rubygems.org"

gemspec path: ".."

gem "sidekiq", "~> 8.1.0"
18 changes: 8 additions & 10 deletions lib/mini_scheduler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "mini_scheduler/manager"
require "mini_scheduler/distributed_mutex"
require "sidekiq"
require "redis"

begin
require "sidekiq/exception_handler"
Expand All @@ -16,26 +17,23 @@ def self.configure
yield self
end

class SidekiqExceptionHandler
if defined?(Sidekiq::ExceptionHandler)
extend Sidekiq::ExceptionHandler
else
def self.handle_exception(exception, context)
Sidekiq.handle_exception(exception, context)
end
SidekiqExceptionHandler =
if defined?(Sidekiq.default_configuration) # Sidekiq 7+
->(ex, ctx, _config = nil) { Sidekiq.default_configuration.handle_exception(ex, ctx) }
else # Sidekiq 6.5
->(ex, ctx, _config = nil) { Sidekiq.handle_exception(ex, ctx) }
end
end

def self.job_exception_handler(&blk)
@job_exception_handler = blk if blk
@job_exception_handler
end

def self.handle_job_exception(ex, context = {})
def self.handle_job_exception(ex, context = {}, _config = nil)
if job_exception_handler
job_exception_handler.call(ex, context)
else
SidekiqExceptionHandler.handle_exception(ex, context)
SidekiqExceptionHandler.call(ex, context)
end
end

Expand Down
10 changes: 5 additions & 5 deletions lib/mini_scheduler/manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def initialize(manager)
@keep_alive_thread =
Thread.new do
while !@stopped
@mutex.synchronize { keep_alive }
sleep(@manager.keep_alive_duration / 2)
@mutex.synchronize { keep_alive }
end
end

Expand Down Expand Up @@ -348,7 +348,7 @@ def blocking_tick
end

def stop!
@runner.stop!
@runner&.stop!
self.class.current.delete(@queue)
end

Expand All @@ -357,7 +357,7 @@ def keep_alive_duration
end

def keep_alive(*ids)
ids = [identity_key, *@runner.worker_thread_ids] if ids.size == 0
ids = [identity_key, *@runner&.worker_thread_ids] if ids.size == 0
ids.each { |identity_key| redis.setex identity_key, keep_alive_duration, "" }
end

Expand Down Expand Up @@ -394,10 +394,10 @@ def self.hostname
begin
require "socket"
Socket.gethostname
rescue => e
rescue StandardError
begin
`hostname`.strip
rescue => e
rescue StandardError
"unknown_host"
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/mini_scheduler/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module MiniScheduler
VERSION = "0.17.0"
VERSION = "0.18.0"
end
30 changes: 16 additions & 14 deletions lib/mini_scheduler/web.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,24 @@ def self.find_schedules_by_time
end
end

def self.registered(app)
app.helpers do
def sane_time(time)
return unless time
time
end
module Helpers
def sane_time(time)
return unless time
time
end

def sane_duration(duration)
return unless duration
if duration < 1000
"#{duration}ms"
else
"#{"%.2f" % (duration / 1000.0)} secs"
end
def sane_duration(duration)
return unless duration
if duration < 1000
"#{duration}ms"
else
"#{"%.2f" % (duration / 1000.0)} secs"
end
end
end

def self.registered(app)
app.helpers Helpers

app.get "/scheduler" do
MiniScheduler.before_sidekiq_web_request&.call
Expand Down Expand Up @@ -72,5 +74,5 @@ def sane_duration(duration)
end
end

Sidekiq::Web.register(MiniScheduler::Web)
Sidekiq::Web.configure {|cfg| cfg.register(MiniScheduler::Web, name: nil, tab: nil, index: nil) }
Sidekiq::Web.tabs["Scheduler"] = "scheduler"
6 changes: 3 additions & 3 deletions mini_scheduler.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/discourse/mini_scheduler"
spec.license = "MIT"

spec.required_ruby_version = ">= 2.7.0"
spec.required_ruby_version = ">= 3.0.0"

spec.files = `git ls-files`.split($/).reject { |s| s =~ /^(spec|\.)/ }
spec.require_paths = ["lib"]

spec.add_runtime_dependency "sidekiq", ">= 4.2.3", "< 7.0"
spec.add_runtime_dependency "sidekiq", ">= 6.5", "< 9.0"

spec.add_development_dependency "pg", "~> 1.0"
spec.add_development_dependency "activesupport", "~> 7.0"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "mocha", "~> 2.0"
spec.add_development_dependency "mocha", "~> 3.0"
spec.add_development_dependency "guard", "~> 2.0"
spec.add_development_dependency "guard-rspec", "~> 4.0"
spec.add_development_dependency "redis", ">= 4.0"
Expand Down
34 changes: 27 additions & 7 deletions spec/mini_scheduler/manager_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -409,26 +409,37 @@ def queued_jobs(manager, with_hostname:)

def expect_job_failure(ex, ctx)
expect(ex).to be_kind_of ZeroDivisionError
expect(ctx).to match(
{ message: "Error while running a scheduled job", job: { "class" => Testing::FailingJob } },
)
expect(ctx).to match a_hash_including(
message: "Error while running a scheduled job",
job: {
"class" => Testing::FailingJob,
},
)
end

context "with default handler" do
class TempSidekiqLogger
attr_accessor :exception, :context

def call(ex, ctx)
def call(ex, ctx, _config = nil)
self.exception = ex
self.context = ctx
end
end

let(:logger) { TempSidekiqLogger.new }

before { Sidekiq.error_handlers << logger }
let(:error_handlers) do
if defined?(Sidekiq.default_configuration)
Sidekiq.default_configuration.error_handlers
else
Sidekiq.error_handlers
end
end

before { error_handlers << logger }

after { Sidekiq.error_handlers.delete(logger) }
after { error_handlers.delete(logger) }

it "captures failed jobs" do
manager.blocking_tick
Expand All @@ -438,7 +449,9 @@ def call(ex, ctx)
end

context "with custom handler" do
before { MiniScheduler.job_exception_handler { |ex, ctx| expect_job_failure(ex, ctx) } }
before do
MiniScheduler.job_exception_handler { |ex, ctx, _config = nil| expect_job_failure(ex, ctx) }
end

after { MiniScheduler.instance_variable_set :@job_exception_handler, nil }

Expand All @@ -447,4 +460,11 @@ def call(ex, ctx)
end
end
end

describe "#keep_alive" do
it "does not raise an error when `skip_runner` is true" do
manager = MiniScheduler::Manager.new(enable_stats: false, skip_runner: true)
expect { manager.keep_alive }.not_to raise_error
end
end
end
Loading