Daemonizing Mailman app - ruby

Starting my mailman app by running rails runner lib/daemons/mailman_server.rb works fine.
When starting with my daemon script and command bundle exec rails runner script/daemon run mailman_server.rb, the script generates an error:
.rvm/gems/ruby-1.9.3-p194/gems/mailman-0.5.3/lib/mailman/route/conditions.rb:21:in `match': undefined method `each' for nil:NilClass (NoMethodError)
My code is as follows:
lib/daemons/mailman_server.rb
require 'mailman'
# Config Mailman
Mailman.config.ignore_stdin = false
Mailman.config.graceful_death = true
Mailman.config.poll_interval = 15
Mailman.config.logger = Logger.new File.expand_path("../../../log/mailman.log", __FILE__)
Mailman.config.pop3 = {
:username => 'alias#mygoogleapp.com',
:password => 'password',
:server => 'pop.gmail.com',
:port => 995,
:ssl => true
}
# Run the mailman
Mailman::Application.run do
from('%email%').to('alias+q%id%#mygoogleapp.com') do |email, id|
begin
# Get message without headers to pass to add_answer_from_email
if message.multipart?
reply = message.text_part.body.decoded
else
reply = message.body.decoded
end
# Call upon the question to add answer to his set
Question.find(id).add_answer_from_email(email, reply)
rescue Exception => e
Mailman.logger.error "Exception occured while receiving message:\n#{message}"
Mailman.logger.error [e, *e.backtrace].join("\n")
end
end
end
and my script/daemon file is:
#!/usr/bin/env ruby
require 'rubygems'
require "bundler/setup"
require 'daemons'
ENV["APP_ROOT"] ||= File.expand_path("#{File.dirname(__FILE__)}/..")
script = "#{ENV["APP_ROOT"]}/lib/daemons/#{ARGV[1]}"
Daemons.run(script, dir_mode: :normal, dir: "#{ENV["APP_ROOT"]}/tmp/pids")
Any insight as to why it fails as a daemon?

Related

rails + heroku: point root in routes.rb file to app.rb file

I have a file called app.rb that runs a server when I run it on my local machine. I would like to deploy app.rb to Heroku so the server will run on Heroku. I think I need to make root in routes.rb point it to. How do I do this?
this is the config.ru:
require_relative 'config/environment'
require '/.app.rb'
run Rails.application
run Sinatra::Application
This is the web server code in app.rb, from codepath guides (https://guides.codepath.com/android/Google-Cloud-Messaging#step-3-setup-web-server):
require 'sinatra'
require 'rest-client'
require 'sequel'
# Create a SQLite3 database
DB = Sequel.connect('sqlite://gcm-test.db')
# Create a Device table if it doesn't exist
DB.create_table? :Device do
primary_key :reg_id
String :user_id
String :reg_token
String :os, :default => 'android'
end
Device = DB[:Device] # create the dataset
# Registration endpoint mapping reg_token to user_id
# POST /register?reg_token=abc&user_id=123
post '/register' do
if Device.filter(:reg_token => params[:reg_token]).count == 0
device = Device.insert(:reg_token => params[:reg_token], :user_id => params[:user_id], :os => 'android')
end
end
# Ennpoint for sending a message to a user
# POST /send?user_id=123&title=hello&body=message
post '/send' do
# Find devices with the corresponding reg_tokens
reg_tokens = Device.filter(:user_id => params[:user_id]).map(:reg_token).to_a
if reg_tokens.count != 0
send_gcm_message(params[:title], params[:body], reg_tokens)
end
end
# Sending logic
# send_gcm_message(["abc", "cdf"])
def send_gcm_message(title, body, reg_tokens)
# Construct JSON payload
post_args = {
# :to field can also be used if there is only 1 reg token to send
:registration_ids => reg_tokens,
:data => {
:title => title,
:body => body,
:anything => "foobar"
}
}
# Send the request with JSON args and headers
RestClient.post 'https://gcm-http.googleapis.com/gcm/send', post_args.to_json,
:Authorization => 'key=' + AUTHORIZE_KEY, :content_type => :json, :accept => :json
end
This is the procfile:
web: bundle exec puma -C config/puma.rb
when I follow the getting started with Ruby on Heroku example, I can see the example webpage. However, if I edit the config.ru file with 'run Sinatra::Application', and deploy to heroku, it is not able to show the example webpage anymore, and just says "Not Found"
require '/.app.rb'
This should be ./app.rb instead.

Handling exceptions in forked process

I'm building a Sinatra API call that will trigger a long-running operation in a subprocess. I'm using the exception_handler gem, but don't understand how I'd use it in the forked process.
Sinatra app:
require 'sinatra'
require 'rubygems'
require 'bundler/setup'
require 'exception_notification'
use ExceptionNotification::Rack,
:email => {
:email_prefix => "[Example] ",
:sender_address => %{"notifier" <notifier#example.com>},
:exception_recipients => %w{me#example.com},
:delivery_method => :sendmail
}
get '/error' do
raise 'Bad!' # Notification gets sent
end
get '/error_async' do
p1 = fork do
sleep 10
raise 'Bad! (async)' # Notification never gets sent
end
Process.detach(p1)
end
Got it working, per the docs:
get '/error_async' do
p1 = fork do
begin
sleep 10
raise 'Bad! (async)'
rescue Exception => e
ExceptionNotifier.notify_exception(e)
end
end
Process.detach(p1)
end

undefined local variable or method `res' for main:Object (NameError)

I have the following little script that connects to a host, and gets some output.
#!/usr/bin/env ruby
require 'net/http'
require 'net/https'
require 'timeout'
serverurl = "http://www.google.com/"
uri = URI(serverurl)
res = Net::HTTP.post_form(uri, 'method' => 'login', 'username' => 'admin', 'password' => 'MySup3rDup3rp#55w0rd')
cookie = res['set-cookie']
if cookie.nil?
puts "No cookie"
end
I want to use some timeout so I do:
#!/usr/bin/env ruby
require 'net/http'
require 'net/https'
require 'timeout'
serverurl = "http://www.google.com/"
uri = URI(serverurl)
begin
timeout(10) do
res = Net::HTTP.post_form(uri, 'method' => 'login', 'username' => 'admin', 'password' => 'MySup3rDup3rp#55w0rd')
end
rescue StandardError,Timeout::Error
puts "#{server} Timeout"
exit(1)
end
cookie = res['set-cookie']
if cookie.nil?
puts "No cookie"
end
Now I get some error:
test.rb:20:in `<main>': undefined local variable or method `res' for main:Object (NameError)
I don't know why, because a similar test code works without error:
require "timeout"
begin
timeout(6) do
sleep
end
#rescue # under ruby >= 1.9 is ok
rescue StandardError,Timeout::Error # workaround for ruby < 1.9
p "I'm sorry, Sir. We couldn't make it, Sir."
end
Any idea what am I doing wrong?
This is about scope. In Ruby, variables are only visible within the same scope where they are defined (exceptions are instance-, class-, and global variables as well as constants).
So in your example, res is only visible within the timeout-block. Add res = nil before the begin-block to make sure res is defined in the scope you actually need the value.

Automatic Airbrake errors with plain Ruby (no Rails or Sinatra)

Is there a way to integrate Airbrake with a pure Ruby project (not rails or sinatra) so that unanticipated errors get reported? I have it set up and I am able to catch errors by calling Airbrake.notify_or_ignore and passing in the exception, but I can't get it to report errors without explicitly calling this.
The following is the code that works for explicitly calling Airbrake.notify but doesn't work for sending errors to Airbrake without explicitly calling notify:
require 'airbrake'
Airbrake.configure do |config|
config.api_key = ENV['AIRBRAKE_API_KEY']
config.development_environments = []
config.ignore_only = []
end
I tried adding Rack as a middleware with the following code:
require 'rack'
require 'airbrake'
Airbrake.configure do |config|
config.api_key = ENV['AIRBRAKE_API_KEY']
config.development_environments = []
config.ignore_only = []
end
app = Rack::Builder.app do
run lambda { |env| raise "Rack down" }
end
use Airbrake::Rack
run app
But I get an "undefined method `use' for main:Object (NoMethodError)"
Any thoughts?
Copied from Mark's comment's link to airbrake for future googlers:
# code at http://gist.github.com/3350
# tests at http://gist.github.com/3354
class Airbrake < ActiveResource::Base
self.site = "http://your_account.airbrake.io"
class << self
##auth_token = 'your_auth_token'
def find(*arguments)
arguments = append_auth_token_to_params(*arguments)
super(*arguments)
end
def append_auth_token_to_params(*arguments)
opts = arguments.last.is_a?(Hash) ? arguments.pop : {}
opts = opts.has_key?(:params) ? opts : opts.merge(:params => {})
opts[:params] = opts[:params].merge(:auth_token => ##auth_token)
arguments << opts
arguments
end
end
end
class Error < Airbrake
end
# Errors are paginated. You get 30 at a time.
#errors = Error.find :all
#errors = Error.find :all, :params => { :page => 2 }

nanoc site tested with unicorn

I have a nanoc site (so, all static pages) that I'd like to test with unicorn.
The idea behind this is to host this site on heroku then.
The structure is then a rack application.
I have added a config.ru file like:
require 'rubygems'
require 'rack'
require 'rack-rewrite'
require 'rack/contrib'
use Rack::Rewrite do
rewrite '/','/output/index.html'
end
use Rack::Static, :urls => ['/'], :root => "output"
(all my static resources are located in the output directory)
When I run unicorn I got the following error message:
NoMethodError at /output/index.html
undefined method `to_i' for #<Rack::Static:0x10165ee18>
I do not really understand what I am missing here :(
Any idea ?
Thanks and regards,
Luc
with this config.ru, it works :)
require 'rubygems'
require 'rack'
require 'rack/contrib'
require 'rack-rewrite'
require 'mime/types'
use Rack::Deflater
use Rack::ETag
module ::Rack
class TryStatic < Static
def initialize(app, options)
super
#try = ([''] + Array(options.delete(:try)) + [''])
end
def call(env)
#next = 0
while #next < #try.size && 404 == (resp = super(try_next(env)))[0]
#next += 1
end
404 == resp[0] ? #app.call : resp
end
private
def try_next(env)
env.merge('PATH_INFO' => env['PATH_INFO'] + #try[#next])
end
end
end
use Rack::TryStatic,
:root => "output", # static files root dir
:urls => %w[/], # match all requests
:try => ['.html', 'index.html', '/index.html'] # try these postfixes sequentially
errorFile='output/404.html'
run lambda { [404, {
"Last-Modified" => File.mtime(errorFile).httpdate,
"Content-Type" => "text/html",
"Content-Length" => File.size(errorFile).to_s
}, File.read(errorFile)] }
Regards,
Luc

Resources