I have an specific requirement to be implemented, and any thoughts on thet would be welcome
The requirement
A given Appointment
model has the following structure:
Appointment {
status, # 'scheduled' or 'done'
happens_at # Datetime
}
The status
attribute that must be changed from scheduled
to done
at the time given by the attribute happens_at
Possible solutions
Scheduling a Job
Using rails Active Job framework, as soon as the tuple is created, we can simply call a Job that will be responsible for setting the status as 'done'
class Appointment < ApplicationRecord
# ...
def after_create
RefreshAppointmentStatusJob.set(wait_until: created_appointment[:happens_at])
.perform_later(created_appointment[:id])
end
end
apparent PROS:
- Easy to implement on creation
apparent CONS:
- Need to handle job rescheduling if
Appointment.happens_at
is updated - What happens if my queue gets corrupted? How to make sure any "lost" scheduling would be rescheduled?
Using cron job running every minute
Then there is this other possible solution, which is basically a cro job running every minute with an implementation like
class RefreshStatusService < ApplicationService
def call
Appointment.where('happens_at <= ?', date).update_all(status: 'done')
end
end
apparent PROS:
- Decouples this feature from Appointment creation/update/delete
- Any problem regarding the queue/cron execution should not interfeer on database consistance after it is fixed (I mean, as soon as the query is run, any outdated status is going to be corretly updated)
apparent CONS:
- Seems "dumb" to run this routine literally every minute, while probably most of thos runs are not updating anything
- Every update will not actually happen on the correct
happens_at
, if it considers the seconds. It means we can have at most ~60 seconds of outdated data, which might be acceptable or not, deppending on the application
Best approach?
I've already implemented both solutions to similar problems, but every time I have to do it again I keep wondering which is the prefered solution. Any thoughts or opinions on thet would be very nice!
Note: I've used Ruby on Rails as example because it has built-in support for queues, but the problem itself would be faced on any other web framework
CodePudding user response:
I have used a third approach... based on the notion that, although status
needs to be done
after the happens_at
date has passed, it really doesn't have to change at that moment, but it must be correctly set the next time anyone queries the object. So use an after_initialize
callback, which will update the value of status
whenever the object is fetched from the db, if the happens_at
is in the past.
class Appointment < ApplicationRecord
after_initialize :set_status
def set_status
update(status: 'done') if happens_at.past?
end
end
CodePudding user response:
and here's yet another approach! Rename the status field to, say, raw_status
and then add a status
method:
class Appointment < ApplicationRecord
def status
return 'done' if happens_at.past?
raw_status
end
end