Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move App Systemd Tasks to Active Jobs #552

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/jobs/application_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class ApplicationJob < ActiveJob::Base
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked

# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end
86 changes: 86 additions & 0 deletions app/jobs/pull_email_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
require 'logger'

class PullEmailJob < ApplicationJob
queue_as :default
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job probably needs a before_perform to schedule the job occurring on the next 20 minute interval. Or, see other comment below we can have a separate job scheduling this job that incorporates the IMAP idle notifications.


def perform(*args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can have no arguments if you aren't using any.

STDOUT.sync = true

logger = Logger.new(STDOUT)
logger.level = Logger::INFO
Comment on lines +7 to +10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we still want these


Rails.application.credentials.fetch(:email) { raise 'Could not find `email` credentials!' }
Rails.application.credentials.email.fetch(:email) { raise 'Could not find `email` in `email` credentials!' }
Rails.application.credentials.email.fetch(:name) { raise 'Could not find `name` in `email` credentials!' }
Rails.application.credentials.email.fetch(:port) { raise 'Could not find `port` in `email` credentials!' }
Rails.application.credentials.email.fetch(:host) { raise 'Could not find `host` in `email` credentials!' }
Rails.application.credentials.email.fetch(:ssl) { raise 'Could not find `ssl` in `email` credentials!' }
# Cannot used nested hashes in credentials without [] in Rails 6
# https://blog.saeloun.com/2021/06/02/rails-access-nested-secrects-by-method-call/
if Rails.application.credentials.email[:oauth].nil? && Rails.application.credentials.email[:password].nil?
raise 'Could not find `oauth` or `password` in `email` credentials!'
elsif !Rails.application.credentials.email[:oauth].nil? && !Rails.application.credentials.email[:password].nil?
raise 'Found both `oauth` and `password` in `email` credentials!'
elsif !Rails.application.credentials.email[:oauth].nil?
Rails.application.credentials.email[:oauth].fetch(:site) { raise 'Could not find `site` in `email.oauth` credentials!' }
Rails.application.credentials.email[:oauth].fetch(:authorize_url) { raise 'Could not find `authorize_url` in `email.oauth` credentials!' }
Rails.application.credentials.email[:oauth].fetch(:token_url) { raise 'Could not find `token_url` in `email.oauth` credentials!' }
Rails.application.credentials.email[:oauth].fetch(:refresh_token) { raise 'Could not find `refresh_token` in `email.oauth` credentials!' }
Rails.application.credentials.email[:oauth].fetch(:client_id) { raise 'Could not find `client_id` in `email.oauth` credentials!' }
Rails.application.credentials.email[:oauth].fetch(:client_secret) { raise 'Could not find `client_secret` in `email.oauth` credentials!' }
end
config = Rails.application.credentials.email

reconnectSleep = 1

Comment on lines +34 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
reconnectSleep = 1

logger.info("Logging in to mailbox #{config[:email]}")

begin
imap = Net::IMAP.new(config[:host], port: config[:port], ssl: config[:ssl])
imap.capable?(:IMAP4rev1) or raise "Not an IMAP4rev1 server"
if imap.auth_capable?("XOAUTH2") && !Rails.application.credentials.email[:oauth].nil?
oauth_client = OAuth2::Client.new(config[:oauth][:client_id], config[:oauth][:client_secret], {site: config[:oauth][:site], authorize_url: config[:oauth][:authorize_url], token_url: config[:oauth][:token_url]})
access_token = OAuth2::AccessToken.from_hash(oauth_client, refresh_token: config[:oauth][:refresh_token]).refresh!
imap.authenticate('XOAUTH2', config[:email], access_token.token)
elsif imap.auth_capable?("PLAIN")
imap.authenticate("PLAIN", config[:email], config[:password])
# Should not use deprecated LOGIN method
# elsif !imap.capability?("LOGINDISABLED")
# imap.login(config[:email], config[:password])
else
raise "No acceptable authentication mechanisms"
end
rescue Net::IMAP::NoResponseError, SocketError, Faraday::ConnectionFailed => error
logger.error("Could not authenticate for #{config[:email]}, error: #{error.message}")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we no longer anticipate rate-limits or connection drops, I changed this (and one below) to log an error. I figure that while it is an error, it is not likely to be one resulting from our app logic, but should it raise an error instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes it should raise an error so that the job is properly marked as failed. We can then set retry_on or discard_on depending on how it errored.

return
end

begin
imap.select(config[:name])

while true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want this while true anymore since we will control the frequency by running the job many times (not a single long-lasting job).

logger.info("Pulling emails for #{config[:email]}")
query = ["BEFORE", Net::IMAP.format_date(Time.now + 1.day)]
latest = Email.order("timestamp DESC").first
query = ["SINCE", Net::IMAP.format_date(latest.timestamp)] if latest

ids = imap.search(query)
imap.fetch(ids, "BODY.PEEK[]").each do |msg|
mail = Mail.new(msg.attr["BODY[]"])

unless Email.where(message_id: mail.message_id).exists?
begin
unless Email.create_from_mail(mail)
logger.error("Could not pull message #{mail.message_id}")
end
rescue Exception => e
logger.error("Exception while loading message #{mail.message_id}: " + e.to_s + "\n" + e.backtrace.join("\n"))
end
end
end
end
rescue Net::IMAP::Error, EOFError, Errno::ECONNRESET => e
logger.error("Disconnected for mailbox #{config[:email]}")
end
end
end
102 changes: 102 additions & 0 deletions app/jobs/send_event_slack_notifications_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
class SendEventSlackNotificationsJob < ApplicationJob
queue_as :default

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job probably needs a before_perform to schedule the job occurring on the next hour interval.

A later PR could break this into two jobs: One to send notifications for each event and one to schedule a notification job for each event (so that it isn't restricted to on the hour). This would also need to keep track of events that have already been notified (and clear that record if the time changes to a later time).

def perform(*args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, unsure that we have to specify args if not used.

Rails.application.routes.default_url_options = Rails.application.config.action_mailer.default_url_options

STDOUT.sync = true

logger = Logger.new(STDOUT)
Comment on lines +7 to +9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want these still for STDOUT



Rails.application.credentials.fetch(:slack) { raise 'Could not find `slack` credentials!' }
Rails.application.credentials.slack.fetch(:token) { raise 'Could not find `token` in `slack` credentials!' }
env_config = Rails.application.credentials.slack

logger.info("Logging into Slack")
Slack.configure do |config|
config.token = env_config[:token]
end
client = Slack::Web::Client.new

channel =
if Rails.env.development?
"#bot-testing"
elsif Rails.env.staging?
"#bot-testing"
else
"#events"
end
channel_social =
if Rails.env.development?
"#bot-testing"
elsif Rails.env.staging?
"#bot-testing"
else
"#social"
end

startdate = DateTime.now
enddate = 1.hour.from_now

calls = Eventdate.where(events: {textable: true, status: Event::Event_Status_Group_Not_Cancelled}).call_between(startdate, enddate).includes(:event).references(:event)
strikes = Eventdate.where(events: {textable: true, status: Event::Event_Status_Group_Not_Cancelled}).strike_between(startdate, enddate).includes(:event).references(:event)

def message_gen(msg, event_url, eventdate)
[
msg,
{
type: "section",
text: {
type: "mrkdwn",
text: msg + "\n_" + eventdate.locations.join(", ") + "_"
},
accessory: {
type: "button",
text: {
type: "plain_text",
text: "View on Tracker",
emoji: true,
},
url: event_url
}
}
]
end

messages = []
messages_social = []
calls.each do |eventdate|
event_url = Rails.application.routes.url_helpers.url_for(eventdate.event).to_s
msg = "Call for <" + event_url + "|" + eventdate.event.title + "> - " + eventdate.description + " is at " + eventdate.effective_call.strftime("%H:%M")
messages.push(message_gen(msg, event_url, eventdate))
messages_social.push(message_gen(msg, event_url, eventdate)) if eventdate.event.textable_social
end
strikes.each do |eventdate|
event_url = Rails.application.routes.url_helpers.url_for(eventdate.event).to_s
msg = "Strike for <" + event_url + "|" + eventdate.event.title + "> - " + eventdate.description + " is at " + eventdate.effective_strike.strftime("%H:%M")
messages.push(message_gen(msg, event_url, eventdate))
messages_social.push(message_gen(msg, event_url, eventdate)) if eventdate.event.textable_social
end

messages_text = messages.map { |msg| msg[0] }
messages_blocks = messages.map { |msg| msg[1] }
messages_social_text = messages_social.map { |msg| msg[0] }
messages_social_blocks = messages_social.map { |msg| msg[1] }

unless messages.empty?
message_text = messages_text.join("\n")

logger.info("Sending message")
client.chat_postMessage(channel: channel, text: message_text, as_user: true, blocks: messages_blocks)
end

unless messages_social.empty?
message_text = messages_social_text.join("\n")

logger.info("Sending social message")
client.chat_postMessage(channel: channel_social, text: message_text, as_user: true, blocks: messages_blocks)
end

end
end
5 changes: 0 additions & 5 deletions app/mailers/admin_mailer.rb

This file was deleted.

3 changes: 0 additions & 3 deletions app/views/admin_mailer/cleanup_backups.text.erb

This file was deleted.

44 changes: 0 additions & 44 deletions deploy/systemd/[email protected]

This file was deleted.

44 changes: 0 additions & 44 deletions deploy/systemd/[email protected]

This file was deleted.

25 changes: 0 additions & 25 deletions deploy/systemd/[email protected]

This file was deleted.

4 changes: 0 additions & 4 deletions lib/tasks/admin.rake

This file was deleted.

Loading