Schedule publishing of a post in a rails 3 blog - cron

I'm developing a website (with Rails 3.1) where limited set of 'writers' are able to write post. 'Moderators' should accept (or decline) the post and schedule the publishing. Until this moment is the development process pretty basic.
There are two publish moments each day. Accepted posts will be placed in some kind of queue. Each day at 10:00am and 4:00pm the oldest accepted post must be published. However, I need also to be able to ** manually set** a date and time when the post going live.
What's the best way to achieve the result? Cron? Background Jobs?

So...
1) have an accepted_at field, which you can also set manually; it's the 'time to go live'.
2)
class Post
scope :ready_to_be_published, lambda{ where(['accepted_at<? and not published', Time.zone.now]).order('accepted_at ASC') }
def accept!(time_to_go_live = nil)
update_attributes!(:accepted_at => time_to_go_live || Time.zone.now)
end
end
3) have a whenever job at 10am and 4pm to run a rake task
task :publish_a_post => :environment do
Post.ready_to_be_published.first.update_attributes!(:published => true)
end

Related

Vote system to my discord bot with nodejs

I'm making a command .report #user that creates a simple poll with 2 buttons added "agree" and "disagree". After certain time i want the bot to register user if agree's is more than disagree.
How can i make my bot count the results of voting after 7 days and then based on this either register on DB an user or send "Report Voting Failed".
What I hope is to be able to store the expiration date of the voting and that on that date the voting stops working and the corresponding action is taken.
You can use setTimeout() for this. setTimeout() takes in two parameters. One, a function which holds your code that will be ran after the time has passed. Two, the amount of time in milliseconds to wait before executing your code.
Here is an example of how to use this.
console.log('1') // will console.log 1 instantly
setTimeout(() => {
console.log('2') // will console.log 2 after 1 second.
},
1000) // 1s = 1000ms
Furthermore, you can use buttons to accomplish the task of reporting. Check out the guide on buttons for more info. Once a button is pushed, see whether it is an Agree or Disagree then do what you must from there. After the seven days is up, make the buttons unable to press, or whatever you want.
You might want to employ a node.js module such as ms to convert 7d into ms. This could be useful as 7 days in milliseconds is 604,800,000. Using ms,
you could do
const sevenDays = ms('7d') // returns 604800000
and then pass that into your setTimeout() function.
like so:
setTimeout(() => {
console.log('The seven days has passed')
}, sevenDays)
Note however your bot will need to stay online for the duration of these 7 days, otherwise it will not run as it has forgotten that the setTimeout() function was used in an earlier instance.

Timestamp For Discord Bot Status

I am using Discord.js Node V12 I am currently trying to find out how to say time elapsed in the status to show how long the bot has been playing game or any activity. But i cannot find anyone who has asked or answered any of these questions.
#client.event
async def on_connect():
await client.change_presence(status=discord.Status.dnd,activity = discord.Game(name = "VALORANT"))
I would like to break this answer into a few significant points:
• The sample code provided is from discord.py ( a discontinued python based library to interact with the API ) which is totally out of context of the whole question itself since you're asking it for discord.js
• There is no actual way to find the time elapsed since a particular activity as of now but you may resort to this:
var uptime = client.uptime; // returns uptime in milliseconds
var hours = uptime / 1000 / 60 / 60 // converts it to hours
/*
Then you may apply the following approach to change your status every hour passes
*/
setInterval(() => {
client.user.setActivity(`Valorant since ${hours} hour(s)`);
}, 3600000); // this would show up as Playing Valorant since 1 hour(s) and subsequently would change every hour if your bot isn't being restarted continuously.
I took a look at the discord.js documentation to examine setting activities and found no such information about timestamps. However, there was a section in the ActivityType that led me to the discord developers documentation and it indicates:
Bots are only able to send name, type, and optionally url.
So it doesn't seem as though you will be able to set the start or end timestamps for an activity as a bot.

node-schedule undoing cancellation

I've been working with node for the first time in a while again and stumbled upon node-schedule, which for the most part has been a breeze, however, I've found resuming a scheduled task after canceling it via job.cancel() pretty difficult.
For the record, I'm using schedule to perform specific actions at a specific date (non-recurring) and under some circumstances cancel the task at a specific date but would later like to resume it.
I tried using job.cancel(true) after cancelling it via plain job.cancel() first as the documentation states that that would reschedule the task, but this has not worked for me. Using job.reschedule() after having cancelled job first yields the same result.
I could probably come up with an unelegant solution, but I thought I'd ask if anyone knows of an elegant one first.
It took me a while to understand node-schedule documentation ^^
To un-cancel a job, You have to give to reschedule some options.
If you don't pass anything to reschedule, this function returns false (Error occured)
For exemple, you can declare options, and pass this variable like this :
const schedule = require('node-schedule');
let options = {rule: '*/1 * * * * *'}; // Declare schedule rules
let job = schedule.scheduleJob(options, () => {
console.log('Job processing !');
});
job.cancel(); // Cancel Job
job.reschedule(options); // Reschedule Job
Hope it helps.

How to use multi-threading in rails 3?

I am sending mail to the users using actionmailer through postmark. This is my code in controller:
#users = User.where(some condition)
#product = Product.find_by_name(some name).first
for user in #users
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
and this my user_mailer.rb
def new_product_arrival(user,product,home_url)
#from = Settings.mailer_from_address
#recipients = user.login
#sent_on = Time.now
#user = user
#product = product
#content_type = "text/html"
#home_url = home_url
end
The problem is that if there are more than 10 users it takes a very long time because of the for loop. I need to know if we can handle this by using multi-threading or background job. I don't want to use background job, but can anyone tell me how to implement the above using multi-threading.
I am using ruby 1.8.7 and rails 3.0.7
There basically two ways to wrap your loop in order to get "multi-threading":
Spwan a thread for each delivery and join them back to the main thread
threads = []
for user in #users
threads << Thread.new do
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
end
threads.each(&:join)
fork over the entire rails app ( pretty messy but the rails app serving the request will respond immediately ) and have the process detached:
process = fork do
for user in #users
UserMailer.new_product_arrival(user, #product, home_url).deliver
end
Process.kill("HUP")
#sends the kill signal to current Process, which is the Rails App sending your emails
end
Process.detach(process)
Hope that helps
our developer Artem recently made a major update to the Postmark gem
which allows you to send emails easily in batches, which should allow you to send emails faster. Check it out.
Try delayed_job gem. This is a database-based background job gem. We used it in an e-commerce website, for example, sending order confirmation emails to users.
These tasks can happen asynchronously in the background, because your Rails app doesn't need
them executed immediately.
um im a rails student from nairobi dev school kenya ..and i think you can give this a try ,..soo what you are having there is the delayed response due to the number of users ..you can try long polling an example
poll = function (){
s.ajax{
url:/'chat.json'
data: { last_time: get last_time () }
}}.done(function(data) {
// handle data
setTimeout(poll,1000);
});
}
try that in your ow way ..this is useful for a real time application..o you can use even action controller:: live ..i think youre farmiliar with threading with rails .also .the above exmples will hep you ,,hopefuly
\

Timer Job Scheduling on DataSheet Entry in SharePoint

I have a list on which I have an ItemUpdated handler.
When I edit using the datasheet view and modify every item, the ItemUpdated event will obviously run for every single item.
In my ItemUpdated event, I want it to check if there is a Timer Job scheduled to run. If there is, then extend the SPOneTimeSchedule schedule of this job to delay it by 5 seconds. If there isn't, then create the Timer Job and schedule it for 5 seconds from now.
I've tried looking to see if the job definition exists in the handler and if it does exist, then extend the schedule by 5 seconds. If it doesn't exist, then create the job definition to run in a minutes time.
MyTimerJob rollupJob = null;
foreach (SPJobDefinition job in web.Site.WebApplication.JobDefinitions)
{
if (job.Name == Constants.JOB_ROLLUP_NAME)
{
rollupJob = (MyTimerJob)job;
}
}
if (rollupJob == null)
{
rollupJob = new MyTimerJob(Constants.JOB_ROLLUP_NAME, web.Site.WebApplication);
}
SPOneTimeSchedule schedule = new SPOneTimeSchedule(DateTime.Now.AddSeconds(5));
rollupJob.Schedule = schedule;
rollupJob.Update();
When I try this out on the server, I get a lot of errors
"An update conflict has occurred, and you must re-try this action. The object MyTimerJob Name=MyTimerJobName Parent=SPWebApplication Name=SharePoint -80 is being updated by NT AUTHORITY\NETWORK SERVICE in the w3wp process
I think the job is probably running for the first time and once running, the other ItemUpdated events are coming in and finding the existing Job definition. It then tries to Update this definition even though it is currently being used. Should I make a new Job Definition name so that it doesn't step on top of the first? Or raise the time to a minute?
I solved this myself by just setting the delay to a minutes time from now regardless of whether a definition is found. This way, while it is busy, it will keep pushing back the scheduling of the job until it is done processing
This is because the event is asynchronous. You'll need to rethink exactly what you're trying to solve with this code and potentially re-factor it.
Maybe you should try using "lock" on the timer job object?

Resources