lib/resque/scheduler/scheduling_extensions.rb in resque-scheduler-4.1.0 vs lib/resque/scheduler/scheduling_extensions.rb in resque-scheduler-4.2.0
- old
+ new
@@ -42,115 +42,91 @@
# :description is just that, a description of the job (optional). If
# params is an array, each element in the array is passed as a separate
# param, otherwise params is passed in as the only parameter to
# perform.
def schedule=(schedule_hash)
- # This operation tries to be as atomic as possible.
- # It needs to read the existing schedules outside the transaction.
- # Unlikely, but this could still cause a race condition.
- #
- # A more robust solution would be to SCRIPT it, but that would change
- # the required version of Redis.
+ @non_persistent_schedules = nil
+ prepared_schedules = prepare_schedules(schedule_hash)
- # select schedules to remove
- if redis.exists(:schedules)
- clean_keys = non_persistent_schedules
- else
- clean_keys = []
+ prepared_schedules.each do |schedule, config|
+ set_schedule(schedule, config, false)
end
- # Start the transaction. If this is not atomic and more than one
- # process is calling `schedule=` the clean_schedules might overlap a
- # set_schedule and cause the schedules to become corrupt.
- redis.multi do
- clean_schedules(clean_keys)
-
- schedule_hash = prepare_schedule(schedule_hash)
-
- # store all schedules in redis, so we can retrieve them back
- # everywhere.
- schedule_hash.each do |name, job_spec|
- set_schedule(name, job_spec)
- end
- end
-
# ensure only return the successfully saved data!
reload_schedule!
end
# Returns the schedule hash
def schedule
@schedule ||= all_schedules
@schedule || {}
end
- # reloads the schedule from redis
+ # reloads the schedule from redis and memory
def reload_schedule!
@schedule = all_schedules
end
# gets the schedules as it exists in redis
def all_schedules
- return nil unless redis.exists(:schedules)
-
- redis.hgetall(:schedules).tap do |h|
- h.each do |name, config|
- h[name] = decode(config)
- end
- end
+ non_persistent_schedules.merge(persistent_schedules)
end
- # clean the schedules as it exists in redis, useful for first setup?
- def clean_schedules(keys = non_persistent_schedules)
- keys.each do |key|
- remove_schedule(key)
- end
- @schedule = nil
- true
- end
-
- def non_persistent_schedules
- redis.hkeys(:schedules).select { |k| !schedule_persisted?(k) }
- end
-
# Create or update a schedule with the provided name and configuration.
#
# Note: values for class and custom_job_class need to be strings,
# not constants.
#
# Resque.set_schedule('some_job', {:class => 'SomeJob',
# :every => '15mins',
# :queue => 'high',
# :args => '/tmp/poop'})
- def set_schedule(name, config)
+ #
+ # Preventing a reload is optional and available to batch operations
+ def set_schedule(name, config, reload = true)
persist = config.delete(:persist) || config.delete('persist')
- redis.pipelined do
- redis.hset(:schedules, name, encode(config))
- redis.sadd(:schedules_changed, name)
- redis.sadd(:persisted_schedules, name) if persist
+
+ if persist
+ redis.hset(:persistent_schedules, name, encode(config))
+ else
+ non_persistent_schedules[name] = decode(encode(config))
end
- config
+
+ redis.sadd(:schedules_changed, name)
+ reload_schedule! if reload
end
# retrive the schedule configuration for the given name
def fetch_schedule(name)
- decode(redis.hget(:schedules, name))
+ schedule[name]
end
- def schedule_persisted?(name)
- redis.sismember(:persisted_schedules, name)
- end
-
# remove a given schedule by name
def remove_schedule(name)
- redis.hdel(:schedules, name)
- redis.srem(:persisted_schedules, name)
+ non_persistent_schedules.delete(name)
+ redis.hdel(:persistent_schedules, name)
redis.sadd(:schedules_changed, name)
+
+ reload_schedule!
end
private
- def prepare_schedule(schedule_hash)
+ # we store our non-persistent schedules in this hash
+ def non_persistent_schedules
+ @non_persistent_schedules ||= {}
+ end
+
+ # reads the persistent schedules from redis
+ def persistent_schedules
+ redis.hgetall(:persistent_schedules).tap do |h|
+ h.each do |name, config|
+ h[name] = decode(config)
+ end
+ end
+ end
+
+ def prepare_schedules(schedule_hash)
prepared_hash = {}
schedule_hash.each do |name, job_spec|
job_spec = job_spec.dup
unless job_spec.key?('class') || job_spec.key?(:class)
job_spec['class'] = name