Rufus Scheduler: How to specify "on the first day of the month, at 8:00am"? - rufus-scheduler

I am trying to configure a schedule that uses the rufus-scheduler gem. I want to create a "once per month" schedule that runs at a specific time. I am trying to use the every syntax for defining it. How can I write this configuration so that it runs every month, on the first day, at 8:00am?

If you read the documentation you link to, you'll notice that rufus-scheduler also has a cron method, here is how you would use it:
require 'rufus-scheduler'
s = Rufus::Scheduler.new
s.cron '0 8 1 * *' do
puts "Hello, it's 8 am on the first day of the month"
end
To answer more squarely, rufus-scheduler "every" syntax doesn't let you specify something like "8am every first day of the month".

Related

How to test jobs which were scheduled (each one min, cron "* * * * *"), but not wait "real" one minute (rufus-scheduler vs virtual time)?

rufus-scheduler lib allows us to schedule tasks
https://github.com/jmettraux/rufus-scheduler
require 'rufus-scheduler'
scheduler = Rufus::Scheduler.new
scheduler.cron '* * * * *' do
# do something every minute
end
In fact, when you want to test your app on top of rufus-scheduler you will need to sleep real 1 min which is too much for typical tests.
For example, in Reactor(Java) they provide StepVerifier.withVirtualTime in order to avoid long-running tests.`:
https://projectreactor.io/docs/core/release/reference/#_manipulating_time
https://www.baeldung.com/reactive-streams-step-verifier-test-publisher#3-testing-time-based-publishers
RxJava - https://medium.com/#vanniktech/taking-control-of-the-time-when-testing-rxjava-code-91b2e5e88bdf
Are there any options for time manipulation within tests for rufus-scheduler or Ruby itself?
Current solution
rufus-scheduler has type in, thus for verification of app skeleton I'm using in=0.001s and sleep 0.4.
Yes, it takes half-of a second in the test but this is much better than 1 minute.
Have a look at
https://github.com/travisjeffery/timecop
https://andycroll.com/ruby/replace-timecop-with-rails-time-helpers-in-rspec/
or other "time travel" tools.
I second #spickermann on "only test your own code".

how can I run ruby script for n-occurrences every X-minutes

I am looking at https://github.com/jmettraux/rufus-scheduler which nicely allows me to schedule and chain events.
But I want the events to stop after, say, the 10th occurrence or after the 24 days.
How do I do this?
My case would be:
run a script which creates the recurring jobs based on intervals and then stops after a given date or occurrence.
This is what I have done.
def run_schedule(url, count, method, interval)
puts "running scheduler"
scheduler = Rufus::Scheduler.new
scheduler.every interval do
binding.pry
attack_loop(url, count, method)
end
end
I am testing my site and want the attack_loop to be scheduled in memory to run against the interval.
But it appears it never hits the binding.pry line.
Normally these schedulers are running via cron jobs. Then the problem with your requirement is cron job doesn't know whether you hit the 10th occurrence or the 24 days as it doesnt keep a track. One possible solution would be to create a separate table to update the cron job details.
I'm thinking a table like,
scheduler_details
- id
- occurrence_count
- created_date
- updated_date
_ scheduler_type
So, now when you run a script, you can create or update the details. (You can search the script by scheduler_type, that way
you can check the number of occurrences
with created date, you can calculate the 24 days
HTH
Good day, you can specify the number of times a job should run:
https://github.com/jmettraux/rufus-scheduler/#times--nb-of-times-before-auto-unscheduling
If you need a more elaborate stop condition, you could do:
scheduler.every interval do |job|
if Time.now > some_max_date
job.unschedule
else
attack_loop(url, count, method)
end
end
But it appears it never hits the binding.pry line.
What has it to do with your issue title? Are you mixing issues?

Running a cron on start-up using Rufus Scheduler 2.x

I'm trying to run a cron on start-up and then midnight every day from that point.
I'm bound by Dashing to use Rufus Scheduler 2.0.24, in which I can't use 'first_in' with the cron command. The command in 3.x I want to replicate is like so...
scheduler.cron '00 00 * * *', :first_in => '0' do
I'm wondering if there is any way around this?
I found this which describes a similar issue - but this will only run the cron at the first instance of the specified allotted time and not immediately.
a plain way of doing it would be:
job =
proc do
puts "hello"
end
job.call
# run it right now
scheduler.cron('00 00 * * *', &job)
But maybe this one is more readable:
job =
scheduler.cron '00 00 * * *' do
puts 'hello'
end
job.block.call
# run it right now
scheduler.join
Thanks for posting a new question, it made everything clear. The question at Rufus Scheduler :first_in option unknown with cron is a bit different.
I know this is about rufus-scheduler 2.0.24, but I'd like to point to a new feature in 3.3.x: https://github.com/jmettraux/rufus-scheduler/issues/214 where you can do job.trigger_off_schedule and it invokes the job right now if overlap, mutex and other job options allow it.
Back to 2.0.24, the shortcut shown above has no refinement, it will run the block right now. The block might already have an instance running now, imagine you have the schedule set for "midnight every night" and you happen to restart at midnight. Hence, I think the first solution above, is best, because it triggers then schedules.

how do I enable recurring reminders for different users in ruby?

Currently, the users for my app set a specific date and time for a single reminder (using the Chronic gem).
I have a cron job which runs every 10 minutes and checks if the time in the reminder is < Time.now at which point, it sends the reminder and marks that reminder as sent.
However, I want them to be able to specify recurring reminders. The customer should be able to say, "Every other day at 10am".
I can use ice_cube for the recurring part it seems. Then I use Chronic to come up with the start time which will have the day and recurring time.
But I don't have a good way to make it recurring since these are not separate events in the data base.
Here is what I have tried:
```
reminder = response.body['results'] #array of recurring reminders with start_epoch and 'via'
d {reminder}
reminder.count.times do |i|
schedule = IceCube::Schedule.new(now = Time.at(reminder[i]['value']['start_epoch'])) # get the initial start day and time
schedule.add_recurrence_rule(IceCube::Rule.daily) #makes this a daily recurring, but how can I allow this to be customizable?
if schedule.next_occurrence(Chronic.parse('today at 12:01AM')) < Time.now # Check if today's occurence has happened yet
bot_response = BotResponse.get_bot_response(bot_client_id, reminder[i]['value']['bot_input_keyword'])
if reminder[i]['value']['via'] == 'slack'
slack_response = BotMessage.send_slack(reminder[i]['value']['slack_channel'],
bot_response[:bot_response])
d {slack_response}
end #if
end #if
end #do
```
Questions:
Is there a way to tell when a reminder has been sent without writing each specific daily reminder to a database?
Is there a more elegant way for the user in a text string to define the recurrence?
Have you considered trying the whenever gem to implement recurring tasks through cron jobs? I think you should be able to set the schedule times dynamically in the whenever schedule.rb file, see related issue here: Rails - Whenever gem - Dynamic values

Using a Rufus-Scheduler event to set more Rufus-Scheduler events

I've got a script where I am trying to use Rufus-Scheduler to create daily schedules at 1am (based around sunrise and sunset). When I run the code it seems to only run the first scheduler event and won't run any events after it. My understanding is Rufus-Scheduler is supposed to spawn a new thread with each schedule but it looks like it is blocking. Do I need to spawn the schedules off on a new thread? Do I need to create a new scheduler instance for each schedule I'm going to create? I've added a test scheduler at the bottom of the code and it doesn't get created.
Here's the portion of code which relates to rufus-scheduler
def get_todays_show()
this_year = Time.now.year
check_sunset
#the time format that comes back isn't reconginzed by rufus scheduler so recreate it with chronic
sunrise = Chronic.parse("#{#local_sunrise.to_s[0,10]} #{#local_sunrise.to_s[11,8]}" )
sunset = Chronic.parse("#{#local_sunset.to_s[0,10]} #{#local_sunset.to_s[11,8]}" )
schedule_array = create_array_from_csv
schedule_array.each do |sub_array|
earlier = Chronic.parse("#{sub_array[0]} #{this_year} 12:00:01 am")
later = Chronic.parse("#{sub_array[1]} #{this_year} 11:59:59")
range = earlier..later
if range.cover?(Time.now)
#scheduler.at sunset do
madrix_call(sub_array[2].strip)
end
#scheduler.at sunrise do
madrix_call(#off_slot)
end
end
end
end
#set up the scheduler
#scheduler = Rufus::Scheduler.start_new(:frequency => 30.0)
#run it once to handle today
get_todays_show
#the schedule to handle the future
#scheduler.cron '1 1 * * *' do
get_todays_show
p #scheduler.jobs
end
#scheduler.cron '* * * * *' do
p "test schedule - #{Time.now}"
end
#scheduler.join
Do I need to spawn the schedules off on a new thread?
No, rufus-scheduler does it for you.
Do I need to create a new scheduler instance for each schedule I'm going to create?
No, not at all.
Have you tried without setting a frequency (using rufus-scheduler's default frequency)?
Although you are not hitting a rufus-scheduler issue, please read: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html
You are not giving any detail about your environment, it's very hard to help you.
Try to iterate from small to big. Have a small schedule thinggy work and then proceed one step after the other.

Resources