Rails app needs to perform task once a month - ruby-on-rails

I'm making an app called book club. Lots of books with votes will be in the system. Each month, on the first of the month, I need the system to automatically promote the book with the highest number of votes to be the "book of the month". The logic to promote a book and ensure only one book of the month exists has already been implemented.
book.promote!
Lovely, huh?
I have me a test case hurr
Given the following books exist:
| title | author | year_published | votes | created_at |
| Lord of the Flies | William Golding | 1954 | 18 | January 12, 2010 |
| The Virgin Suicides | Jeffrey Eugenides | 1993 | 12 | February 15, 2010 |
| Island | Richard Laymon | 1991 | 6 | November 22, 2009 |
And the book "Lord of the Flies" is the current book of the month
And the date is "February 24, 2010"
Then the book "Lord of the Flies" should be the current book of the month
When the date is "March 1, 2010"
And I am on the home page
Then I should see "This Month's Book of the Month Club Book"
And I should see "The Virgin Suicides"
And the book "The Virgin Suicides" should be the current book of the month
And the book "Lord of the Flies" should not be the current book of the month
And the book "Island" should not be the current book of the month
And I'm trying to get that passing.
So the question is, how do I best implement an automated, once a month update that can be tested by this scenario?
Cron is a bit too sloppy for my taste. I would like a more portable solution.
delayed_job/Resque seems a bit too heavy for the situation. Also I'm a bit unsure of how to get them to run jobs once a month.
Just looking for a simple, but robust, and TESTABLE solution.
Cheers, as always!

I use delayed_job for this type of requirements.
class Book
def promote
# code for the promote method..
ensure
# re-run the task in another 30 days.
promote
end
# Date.today.nextmonth.beginning_of_month will be evaluated
#when promote is called
handle_asynchronously :promote, :run_at => Proc.new {
Date.today.next_month.beginning_of_month
}
end

A nice way to manage periodic tasks is with whenever: https://github.com/javan/whenever
I does use OS cron, but all the config lives inside your rails app, so it's nicer to work with.
However, while it's quite appropriate for maintenance type tasks where, say, if for some reason something doesn't run exactly at the top of the hour or gets skipped over for some reason, the slack will be picked up the next time, in your case where the periodic thing is part of the task, it's a tougher call.
Maybe the app can just "always" ask itself if it's the first of the month yet when the rankings view loads, and if it is, it will do the tally, using only votes within the appropriate date range?
And to test time-dependent behavior, checkout out timecop: https://github.com/jtrupiano/timecop

As John started to say Cron/whenever is the way to go here. Other background daemons require a separate process that will be idle most of the time. You shouldn't have any portability issues with cron unless you're concerned about running on Windows.

We are talking about 2 different things here:
A job that runs and performs task for the system: That would be through rake, it is pretty reliable and well tested.
A scheduler, which runs this task on a schedule you specify. It seems you are looking for alternatives to cron. You can try launchd for this.

delayed_job is really a good choice. You are currently testing with a small number of books, so the promote calculation is done fairly quickly.
When your app scales, you will want to run this calculation in a separate worker process to reduce the impact on the User Experience. delayed_job will kill two birds with one stone: provide a scheduling mechanism and offload the promote calculation to a separate worker process.

Related

Jira JQL: how to find the busiest hours of a queue?

Jira Server v7.12.1#712002
We have noticed that at certain periods of the day there are more tickets assigned to "Operations" queue than usual, so we need to back this impression with real statistics.
We extracted all the tickets that at some point were assigned to "Operations" queue via the following query:
project = "Client Services" AND assignee WAS "Operations"
The results of the query above include the timestamp value in the "Updated" field, however this field reflects the last time the ticket was updated - not what we want. We want a timestamp which shows when the ticket arrived to "Operations" queue.
The tickets can arrive in two ways:
1) Ticket may come from other teams. In such cases, under History tab we can observe how 3 different fields change their values. For example, if ticket comes from certain Joe Smith, it would look like this:
FIELD ORIGINAL VALUE NEW VALUE
Joe Smith made changes - 09/04/2020 12:08
Assignee Joe Smith Operations
2) Ticket may be created directly (by other teams). In such cases the first 2 entries under History tab always have this pattern:
Joe Smith created issue - 02/04/2020 19:27
_______________________________________________________________________________________________________
Joe Smith made changes - 02/04/2020 19:27
FIELD ORIGINAL VALUE NEW VALUE
Link Referred from ABC-12345
The pattern above is that created issue and made changes always have the identical timestamps.
Based on these examples, is there some way to extract the timestamps of all tickets' arrival to "Operations" queue? If not with JQL, maybe some other solution/tool exists?
There can be two ways you could achieve most of what you've asked for:
Use Recently Created Chart JIRA gadget.
With this, you could get a clear picture of number of tickets that you'd get in an hour of a day.
Or you could use the Created Vs Resolved built-in JIRA report
This helps in bringing out better information from the tickets, do some analysis etc.
You could find more details from this answer on Atlassian Community forum. Hope this answer helps!

Rails - handling multiple different time zones on the same request

I'm looking to display data across more than one time zone in the same view in a Rails app for a time and attendance system. A bit of context:
We make electronic time clocks. People but them in their businesses. Staff clock in and out of work and it records their hours.
The time clock pushes the time that someone clocked in/out to our API as a unix time (for example, our Javascript time clock implementation grabs the clock in time like so: moment().unix()). The API then stores this in a Postgres database as a timestamp without time zone.
When a user logs in to the site, an around_filter sets the appropriate time zone for the request based on a setting for this user's organisation.
The problem occurs if we have an organisation that spans multiple time zones. For example, a business that has an office in every Australian capital city will span three time zones (more during DST). However, there will be one person in a central office who will need to check data across the organisation - we'll call them our manager.
Suppose our manager is based in Sydney, and it's 11am. They manage three offices - one in Sydney, one in Brisbane (an hour behind Sydney during DST), and one in Adelaide (half an hour behind Sydney during DST). Staff clocked in at the three offices at 9am in their local times. So, on the manager's dashboard, all the times of the clock-ins should show up as 9am. However, the current implementation (using an around_filter) will show the times as 9am, 8am, and 8:30am, respectively, because they will be offset using the Sydney time zone.
There is a layer of filtering applied to staff from different cities, so it is possible to tell the system that person A is from Sydney, person B is from Adelaide, and person C is from Brisbane. The issue - which I'd like advice on - is how best to get Rails to display offset to different time zones as efficiently as possible.
Bonus credit: as well as showing times, we also need to read input. For example, someone may have clocked in 5 minutes early, and their timesheet needs to be corrected. If a local manager (ie. someone in Brisbane) corrects the timesheet for a Brisbane employee then that should be relatively easy to manage - given we know they are in Brisbane, we can just set the request's time zone to Brisbane and let ActiveRecord do the offsetting for us. But if the general manager (who is based in Sydney but manages all time zones) wants to make the change, then we need to be able to correctly convert their input back into UTC based on their time zone. Any suggestions on how best to do this would be wonderful.
Concrete example of the issue
In my database, my clock_ins table looks like this:
user_id (integer) | time (timestamp without time zone)
------------------|-----------------------------------
1 | "2012-09-25 22:00:00.0"
2 | "2012-09-25 22:30:00.0"
3 | "2012-09-25 23:00:00.0"
And my users table looks like this:
user_id (integer) | time_zone (varchar)
------------------|-----------------------------------
1 | "Sydney"
2 | "Adelaide"
3 | "Brisbane"
(this is a simplification, in reality there is another join between a user and their time zone)
If we apply each user's time zone to the time of their clock in, we find they are all at 9am local time. ie. 2012-09-25 23:00:00.0 at UTC is 2012-09-26 09:00:00.0 in Brisbane (+1000). The general approach in Rails is to use an around_filter to set the time zone for a request; if I did that here, each of the times would be displayed half an hour apart, which is not correct. So I'm looking on advice on best practices when working with times from various zones.
The simplest way I can see is to use the Time.use_zone method when rendering your times. e.g.
Time.use_zone('Sydney') { Time.current }
Time.use_zone(person.office.time_zone) { person.clock_ins.last.time_stamp }
This "Allows override of Time.zone locally inside supplied block; resets Time.zone to existing value when done."

Proposed Simple Scheduling/Availability Database Schema

For this application, staff need to be able setup when they start & end each day of the week. They can optionally have that start/end repeat every 1, 2, or 4 weeks. For example, I start work at 9am and finish at 2pm every Monday. With simple recurrences like that, I'm thinking of having 3, maybe 2 models (for denormalization):
Event
- start: datetime
- end: datetime
- type: int (appointment, time off, cancelled, etc)
- date: date (useful?)
- staff_id: int
- customer_id: int
(more, redacted)
DayTemplate
- active_start: datetime
- active_end: datetime
- staff_id: int
Day
- weekday: int
- start: datetime
- end: datetime
- recurrence: int (0: none, 1: once/mo, 2: other week, 4: every week)
- day_template_id: int
The idea is that the parameters are now set, so customers can go in and book a staff when they're available (in specific chunks, say 9am, 10:15am, 11:30 -- to allow for breaks to be setup). For any day on the schedule, you can easily query for that staff members active DayTemplate. Staff can then further tweak the schedule by booking events as "time off" to give them fine-tune control. Additionally, I was thinking of denormalizing Day into DayTemplate - I know it would look ugly, but the schema would never change, and the performance benefits would make it worth it? Is this enough flexibility?
Appreciate the feedback. I'll be building this in rails.
For this application, staff need to be able setup when they start & end each day of the week. They can optionally have that start/end repeat every 1, 2, or 4 weeks. For example, I start work at 9am and finish at 2pm every Monday. With simple recurrences like that, I'm thinking of having 3, maybe 2 models (for denormalization):
Dont denormalize yet. Focus on getting the business rules down, then map those to business objects in rails. Let the schema design be driven by specific app requirements.
Additionally, I was thinking of denormalizing Day into DayTemplate - I know it would look ugly, but the schema would never change, and the performance benefits would make it worth it?
For sure you should not be worrying about optimizing for performance at this point. Instead optimize for clarity and simplicity. Chances are the aspects of your app that will need performance optimization will be totally different than what you would have guessed upfront.
Is this enough flexibility?
Maybe too much. I'd recommend building the simplest possible thing you can that meets the minimum acceptance criteria. Don't try and engineer in flexibility, it's too hard to guess upfront what kind of flexibility will be required. Over time the cost of maintaining all of these "maybe-we-will-need-this-someday" features will get in the way of building stuff your real users actually want. It's counter-intuitive but keeping things as simple as possible now is the best way end up with a really feature-rich system down the line. Optimize for speed-to-deliver, get it in the hands of real users and start collecting feedback.
Also, the thing about building any kind of scheduling system is that the complexity gets out of hand really quickly. If you're doing this as an exercise it may be worth it to try and code yourself, but if this is something you really need to get done seriously consider using one of the many ruby gems designed to help with modeling/scheduling recurring events. Personally I have used ice cube but there are many choices at the ruby toolbox

Opening hours in ice_cube

How am I able to rule opening hours of a restaurant within single Schedule?
Mon-Fri 8-16 is quite easy:
schedule = Schedule.new(Time.parse(Date.yesterday.to_s + ' 8:00'), :duration => 60*60*8)
(...)
schedule.add_recurrence_rule Rule.daily.day(:wednesday)
schedule.add_recurrence_rule Rule.daily.day(:thursday)
(...)
schedule.occurring_at?(Time.now)
Problem is when trying to rule something like:
Mon 9-17,
Tu 16-01 (the next day after midnight)
etc.
Am I able to do this with that plugin?
Just got email from an Ice_Cube author answering my question. Might be usefull:
Unfortunately we strive to maintain backwards compatibility with the iCalendar standard - so you can't change durations on a per-rule basis. If you want to accomplish something like the above, people either use multiple schedules, or store the durations separately (the latter is highly preferred)

rails activerecord statistics/trends/time-series graph data

We are in the process of building dashboards for users where in they can see the trends/time series graphs of various activerecords; take a blogging site as an example. There are posts, each post has many comments and tags. There are 2 kinds of dashboards to be built.
a. trend graphs
b. time series graphs
trends graphs:
example, trending tags ( top 10, with # of posts), the ui looks like this
today [week] [month]
ruby-on-rails(20)
activerecord(10)
java(5)
When the user click on week, the trend shows the weekly data and so on.
And similarly, another trend graph is top 10 posts with highest # of comments
time series graphs:
for example, time vs # of posts, over a period of 24 hours, 1 week, 1 month etc.,
30
20 |
10 | | 10
| | | |
t1 t2 t3 t4
a visual example
Secondary Requirement:
The time series graphs cane be interactive and we may want show the actual data or additional series when a point is selected. Additional series: for example when the user selects point (t3,30) we want to show the tag name vs #count data.
ruby-on-rails(15)
activerecord(10)
java(5)
I have looked at statistics gem and it is good for generating counts but not graph data.
Question
Is there a gem(framework) to generate data for these graphs?. In our case, the graph data can be cached and refreshed every 15/30 minutes.
Is there any reason why you need a gem? A place that I've worked used Highcharts in combination with Ruby/Rails and that worked. You could also use the Google Chart API. I'm not sure how much you want to build out what you're doing, but you can create tables in a sql database that track whatever you want to be tracking, and then just feed those to the charting tool
Also, here are several services with API's that offer this kind of graphing capability.
StatsMix, Metricly, myDials, KPI Dashboard, and more

Resources