README.md in rufus-scheduler-3.0.8 vs README.md in rufus-scheduler-3.0.9
- old
+ new
@@ -87,10 +87,12 @@
## getting help
So you need help. People can help you, but first help them help you, and don't waste their time. Provide a complete description of the issue. If it works on A but not on B and others have to ask you: "so what is different between A and B" you are wasting everyone's time.
+"hello" and "thanks" are not swear words.
+
Go read [how to report bugs effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html), twice.
Update: [help_help.md](https://gist.github.com/jmettraux/310fed75f568fd731814) might help help you.
### on StackOverflow
@@ -1095,10 +1097,61 @@
This is useful in environments where the Ruby process holding the scheduler gets started multiple times.
If the lockfile mechanism here is not sufficient, you can plug your custom mechanism. It's explained in [advanced lock schemes](#advanced-lock-schemes) below.
+### :scheduler_lock
+
+(since rufus-scheduler 3.0.9)
+
+The scheduler lock is an object that responds to `#lock` and `#unlock`. The scheduler calls `#lock` when starting up. If the answer is `false`, the scheduler stops its initialization work and won't schedule anything.
+
+Here is a sample of a scheduler lock that only lets the scheduler on host "coffee.example.com" start:
+```ruby
+class HostLock
+ def initialize(lock_name)
+ @lock_name = lock_name
+ end
+ def lock
+ @lock_name == `hostname -f`.strip
+ end
+ def unlock
+ true
+ end
+end
+
+scheduler =
+ Rufus::Scheduler.new(:scheduler_lock => HostLock.new('coffee.example.com'))
+```
+
+By default, the scheduler_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that returns true.
+
+### :trigger_lock
+
+(since rufus-scheduler 3.0.9)
+
+The trigger lock in an object that responds to `#lock`. The scheduler calls that method on the job lock right before triggering any job. If the answer is false, the trigger doesn't happen, the job is not done (at least not in this scheduler).
+
+Here is a (stupid) PingLock example, it'll only trigger if an "other host" is not responding to ping. Do not use that in production, you don't want to fork a ping process for each trigger attempt...
+```ruby
+class PingLock
+ def initialize(other_host)
+ @other_host = other_host
+ end
+ def lock
+ ! system("ping -c 1 #{@other_host}")
+ end
+end
+
+scheduler =
+ Rufus::Scheduler.new(:trigger_lock => PingLock.new('main.example.com'))
+```
+
+By default, the trigger_lock is an instance of `Rufus::Scheduler::NullLock`, with a `#lock` that always returns true.
+
+As explained in [advanced lock schemes](#advanced-lock-schemes), another way to tune that behaviour is by overriding the scheduler's `#confirm_lock` method. (You could also do that with an `#on_pre_trigger` callback).
+
### :max_work_threads
In rufus-scheduler 2.x, by default, each job triggering received its own, brand new, thread of execution. In rufus-scheduler 3.x, execution happens in a pooled work thread. The max work thread count (the pool size) defaults to 28.
One can set this maximum value when starting the scheduler.
@@ -1180,9 +1233,23 @@
The methods #lock and #unlock are overriden and #confirm_lock is provided,
to make sure that the lock is still valid.
The #confirm_lock method is called right before a job triggers (if it is provided). The more generic callback #on_pre_trigger is called right after #confirm_lock.
+
+### :scheduler_lock and :trigger_lock
+
+(introduced in rufus-scheduler 3.0.9).
+
+Another way of prodiving `#lock`, `#unlock` and `#confirm_lock` to a rufus-scheduler is by using the `:scheduler_lock` and `:trigger_lock` options.
+
+See [:trigger_lock](#trigger_lock) and [:scheduler_lock](#scheduler_lock).
+
+The scheduler lock may be used to prevent a scheduler from starting, while a trigger lock prevents individual jobs from triggering (the scheduler goes on scheduling).
+
+One has to be careful with what goes in `#confirm_lock` or in a trigger lock, as it gets called before each trigger.
+
+Warning: you may think you're heading towards "high availability" by using a trigger lock and having lots of schedulers at hand. It may be so if you limit yourself to scheduling the same set of jobs at scheduler startup. But if you add schedules at runtime, they stay local to their scheduler. There is no magic that propagates the jobs to all the schedulers in your pack.
## parsing cronlines and time strings
Rufus::Scheduler provides a class method ```.parse``` to parse time durations and cron strings. It's what it's using when receiving schedules. One can use it diectly (no need to instantiate a Scheduler).