Commit 72a1c96d0f7bb0345cc7f06e89942cf4b58de9f6
Exists in
master
and in
29 other branches
Merge branch 'stable' into postgres-tests
Showing
19 changed files
with
151 additions
and
52 deletions
Show diff stats
app/models/profile.rb
| ... | ... | @@ -298,7 +298,7 @@ class Profile < ActiveRecord::Base |
| 298 | 298 | validate :valid_template |
| 299 | 299 | |
| 300 | 300 | def valid_template |
| 301 | - if template_id.present? and !template.is_template | |
| 301 | + if template_id.present? && template && !template.is_template | |
| 302 | 302 | errors.add(:template, _('is not a template.')) |
| 303 | 303 | end |
| 304 | 304 | end | ... | ... |
app/views/blocks/location.html.erb
| 1 | 1 | <% if profile.lat %> |
| 2 | 2 | <%= block_title block.title %> |
| 3 | 3 | <div class='the-localization-map'> |
| 4 | - <img src="http://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/> | |
| 4 | + <img src="https://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/> | |
| 5 | 5 | </div> |
| 6 | 6 | </div> |
| 7 | 7 | <% else %> | ... | ... |
app/views/maps/edit_location.rhtml
| ... | ... | @@ -29,5 +29,5 @@ |
| 29 | 29 | |
| 30 | 30 | <% end %> |
| 31 | 31 | |
| 32 | -<%= content_tag('script', '', :src => "http://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %> | |
| 32 | +<%= content_tag('script', '', :src => "https://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %> | |
| 33 | 33 | <%= content_tag('script', '', :src => url_for(:controller => :maps, :action => :google_map), :type => 'text/javascript') %> | ... | ... |
db/schema.rb
| ... | ... | @@ -221,7 +221,6 @@ ActiveRecord::Schema.define(:version => 20130711213046) do |
| 221 | 221 | t.string "source_type" |
| 222 | 222 | t.string "user_agent" |
| 223 | 223 | t.string "referrer" |
| 224 | - t.integer "group_id" | |
| 225 | 224 | end |
| 226 | 225 | |
| 227 | 226 | add_index "comments", ["source_id", "spam"], :name => "index_comments_on_source_id_and_spam" | ... | ... |
debian/changelog
lib/feed_updater.rb
| ... | ... | @@ -19,6 +19,18 @@ end |
| 19 | 19 | # stops the process. |
| 20 | 20 | class FeedUpdater |
| 21 | 21 | |
| 22 | + class ExceptionNotification < ActionMailer::Base | |
| 23 | + def mail error | |
| 24 | + environment = Environment.default | |
| 25 | + | |
| 26 | + recipients NOOSFERO_CONF['exception_recipients'] | |
| 27 | + from environment.contact_email | |
| 28 | + reply_to environment.contact_email | |
| 29 | + subject "[#{environment.name}] Feed-updater: #{error.message}" | |
| 30 | + body render(:text => error.backtrace.join("\n")) | |
| 31 | + end | |
| 32 | + end | |
| 33 | + | |
| 22 | 34 | # indicates how much time one feed will be left without updates |
| 23 | 35 | # (ActiveSupport::Duration). Default: <tt>4.hours</tt> |
| 24 | 36 | cattr_accessor :update_interval |
| ... | ... | @@ -79,6 +91,8 @@ class FeedUpdater |
| 79 | 91 | feed_handler.process(container) |
| 80 | 92 | end |
| 81 | 93 | end |
| 94 | + rescue Exception => e | |
| 95 | + FeedUpdater::ExceptionNotification.deliver_mail e if NOOSFERO_CONF['exception_recipients'].present? | |
| 82 | 96 | end |
| 83 | 97 | end |
| 84 | 98 | ... | ... |
lib/noosfero.rb
plugins/solr/lib/solr_plugin/search_helper.rb
| ... | ... | @@ -34,10 +34,6 @@ module SolrPlugin::SearchHelper |
| 34 | 34 | ], |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | -# def asset_class(asset) | |
| 38 | -# asset.to_s.singularize.camelize.constantize | |
| 39 | -# end | |
| 40 | - | |
| 41 | 37 | def class_asset(klass) |
| 42 | 38 | klass.name.underscore.pluralize.to_sym |
| 43 | 39 | end |
| ... | ... | @@ -111,6 +107,8 @@ module SolrPlugin::SearchHelper |
| 111 | 107 | |
| 112 | 108 | def asset_class(asset) |
| 113 | 109 | asset.to_s.singularize.camelize.constantize |
| 110 | + rescue | |
| 111 | + asset.to_s.singularize.camelize.gsub('Plugin', 'Plugin::').constantize | |
| 114 | 112 | end |
| 115 | 113 | |
| 116 | 114 | def set_facets_variables | ... | ... |
plugins/solr/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb
| ... | ... | @@ -208,7 +208,7 @@ module ActsAsSolr #:nodoc: |
| 208 | 208 | # using eager loading for indexed associations. |
| 209 | 209 | def rebuild_solr_index(batch_size=300, options = {}, &finder) |
| 210 | 210 | finder ||= lambda do |ar, sql_options| |
| 211 | - ar.all sql_options.merge!({:order => self.primary_key, :include => configuration[:solr_includes].keys}) | |
| 211 | + ar.all sql_options.merge!({:order => self.primary_key}) | |
| 212 | 212 | end |
| 213 | 213 | start_time = Time.now |
| 214 | 214 | options[:offset] ||= 0 | ... | ... |
plugins/solr/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb
| 1 | 1 | module ActsAsSolr #:nodoc: |
| 2 | - | |
| 2 | + | |
| 3 | 3 | module InstanceMethods |
| 4 | 4 | |
| 5 | 5 | # Solr id is <class.name>:<id> to be unique across all models |
| ... | ... | @@ -10,7 +10,7 @@ module ActsAsSolr #:nodoc: |
| 10 | 10 | # saves to the Solr index |
| 11 | 11 | def solr_save |
| 12 | 12 | return true if indexing_disabled? |
| 13 | - if evaluate_condition(:if, self) | |
| 13 | + if evaluate_condition(:if, self) | |
| 14 | 14 | debug "solr_save: #{self.class.name} : #{record_id(self)}" |
| 15 | 15 | solr_add to_solr_doc |
| 16 | 16 | solr_commit if configuration[:auto_commit] |
| ... | ... | @@ -38,9 +38,9 @@ module ActsAsSolr #:nodoc: |
| 38 | 38 | debug "to_solr_doc: creating doc for class: #{self.class.name}, id: #{record_id(self)}" |
| 39 | 39 | doc = Solr::Document.new |
| 40 | 40 | doc.boost = validate_boost(configuration[:boost]) if configuration[:boost] |
| 41 | - | |
| 41 | + | |
| 42 | 42 | doc << {:id => solr_id, |
| 43 | - solr_configuration[:type_field] => self.class.name, | |
| 43 | + solr_configuration[:type_field] => Solr::Util.query_parser_escape(self.class.name), | |
| 44 | 44 | solr_configuration[:primary_key_field] => record_id(self).to_s} |
| 45 | 45 | |
| 46 | 46 | # iterate through the fields and add them to the document, |
| ... | ... | @@ -50,7 +50,7 @@ module ActsAsSolr #:nodoc: |
| 50 | 50 | field_boost = options[:boost] || solr_configuration[:default_boost] |
| 51 | 51 | field_type = get_solr_field_type(options[:type]) |
| 52 | 52 | solr_name = options[:as] || field_name |
| 53 | - | |
| 53 | + | |
| 54 | 54 | value = self.send("#{field_name}_for_solr") rescue nil |
| 55 | 55 | next if value.nil? |
| 56 | 56 | |
| ... | ... | @@ -63,18 +63,18 @@ module ActsAsSolr #:nodoc: |
| 63 | 63 | field.boost = processed_boost |
| 64 | 64 | doc << field |
| 65 | 65 | end |
| 66 | - | |
| 66 | + | |
| 67 | 67 | add_dynamic_attributes(doc) |
| 68 | 68 | add_includes(doc) |
| 69 | 69 | add_tags(doc) |
| 70 | 70 | add_space(doc) |
| 71 | - | |
| 71 | + | |
| 72 | 72 | debug doc.to_json |
| 73 | 73 | doc |
| 74 | 74 | end |
| 75 | 75 | |
| 76 | 76 | private |
| 77 | - | |
| 77 | + | |
| 78 | 78 | def debug(text) |
| 79 | 79 | logger.debug text rescue nil |
| 80 | 80 | end |
| ... | ... | @@ -85,14 +85,14 @@ module ActsAsSolr #:nodoc: |
| 85 | 85 | doc << Solr::Field.new(:name => "lng_f", :value => local.longitude) |
| 86 | 86 | end |
| 87 | 87 | end |
| 88 | - | |
| 88 | + | |
| 89 | 89 | def add_tags(doc) |
| 90 | 90 | taggings.each do |tagging| |
| 91 | 91 | doc << Solr::Field.new(:name => "tag_facet", :value => tagging.tag.name) |
| 92 | 92 | doc << Solr::Field.new(:name => "tag_t", :value => tagging.tag.name) |
| 93 | 93 | end if configuration[:taggable] |
| 94 | 94 | end |
| 95 | - | |
| 95 | + | |
| 96 | 96 | def add_dynamic_attributes(doc) |
| 97 | 97 | dynamic_attributes.each do |attribute| |
| 98 | 98 | value = ERB::Util.html_escape(attribute.value) |
| ... | ... | @@ -130,7 +130,7 @@ module ActsAsSolr #:nodoc: |
| 130 | 130 | end |
| 131 | 131 | end |
| 132 | 132 | end |
| 133 | - | |
| 133 | + | |
| 134 | 134 | def include_value(record, options) |
| 135 | 135 | if options[:using].is_a? Proc |
| 136 | 136 | options[:using].call(record) |
| ... | ... | @@ -159,14 +159,14 @@ module ActsAsSolr #:nodoc: |
| 159 | 159 | self.send(boost) |
| 160 | 160 | end |
| 161 | 161 | end |
| 162 | - | |
| 162 | + | |
| 163 | 163 | boost_value || solr_configuration[:default_boost] |
| 164 | 164 | end |
| 165 | - | |
| 165 | + | |
| 166 | 166 | def condition_block?(condition) |
| 167 | 167 | condition.respond_to?("call") && (condition.arity == 1 || condition.arity == -1) |
| 168 | 168 | end |
| 169 | - | |
| 169 | + | |
| 170 | 170 | def evaluate_condition(which_condition, field) |
| 171 | 171 | condition = configuration[which_condition] |
| 172 | 172 | case condition | ... | ... |
plugins/solr/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb
| ... | ... | @@ -127,7 +127,7 @@ module ActsAsSolr #:nodoc: |
| 127 | 127 | classes = [self] + (self.subclasses || []) + (options[:models] || []) |
| 128 | 128 | classes.map do |klass| |
| 129 | 129 | next if klass.name.empty? |
| 130 | - "#{solr_configuration[:type_field]}:\"#{klass.name}\"" | |
| 130 | + "#{solr_configuration[:type_field]}:\"#{Solr::Util.query_parser_escape klass.name}\"" | |
| 131 | 131 | end.compact.join(' OR ') |
| 132 | 132 | end |
| 133 | 133 | ... | ... |
plugins/solr/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb
| ... | ... | @@ -12,22 +12,22 @@ |
| 12 | 12 | |
| 13 | 13 | # "Abstract" base class, only useful with subclasses that add parameters |
| 14 | 14 | class Solr::Request::Select < Solr::Request::Base |
| 15 | - | |
| 15 | + | |
| 16 | 16 | attr_reader :query_type |
| 17 | - | |
| 17 | + | |
| 18 | 18 | def initialize(qt=nil, params={}) |
| 19 | 19 | @query_type = qt |
| 20 | 20 | @select_params = params |
| 21 | 21 | end |
| 22 | - | |
| 22 | + | |
| 23 | 23 | def response_format |
| 24 | 24 | :ruby |
| 25 | 25 | end |
| 26 | - | |
| 26 | + | |
| 27 | 27 | def handler |
| 28 | 28 | 'select' |
| 29 | 29 | end |
| 30 | - | |
| 30 | + | |
| 31 | 31 | def content_type |
| 32 | 32 | 'application/x-www-form-urlencoded; charset=utf-8' |
| 33 | 33 | end |
| ... | ... | @@ -35,7 +35,7 @@ class Solr::Request::Select < Solr::Request::Base |
| 35 | 35 | def to_hash |
| 36 | 36 | return {:qt => query_type, :wt => 'ruby', 'json.nl' => 'arrarr'}.merge(@select_params) |
| 37 | 37 | end |
| 38 | - | |
| 38 | + | |
| 39 | 39 | def to_s |
| 40 | 40 | raw_params = self.to_hash |
| 41 | 41 | |
| ... | ... | @@ -50,5 +50,5 @@ class Solr::Request::Select < Solr::Request::Base |
| 50 | 50 | |
| 51 | 51 | http_params.join("&") |
| 52 | 52 | end |
| 53 | - | |
| 53 | + | |
| 54 | 54 | end | ... | ... |
plugins/solr/vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake
| 1 | 1 | namespace :solr do |
| 2 | 2 | |
| 3 | - APACHE_MIRROR = ENV['APACHE_MIRROR'] || "http://ftp.unicamp.br/pub/apache" | |
| 3 | + APACHE_MIRROR = ENV['APACHE_MIRROR'] || "https://archive.apache.org/dist" | |
| 4 | 4 | SOLR_VERSION = '3.6.2' |
| 5 | 5 | SOLR_FILENAME = "apache-solr-#{SOLR_VERSION}.tgz" |
| 6 | 6 | SOLR_MD5SUM = 'e9c51f51265b070062a9d8ed50b84647' |
| ... | ... | @@ -177,7 +177,7 @@ namespace :solr do |
| 177 | 177 | models.each do |model| |
| 178 | 178 | if clear_first |
| 179 | 179 | puts "Clearing index for #{model}..." |
| 180 | - ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "#{model.solr_configuration[:type_field]}:#{Solr::Util.query_parser_escape(model.name)}")) | |
| 180 | + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "#{model.solr_configuration[:type_field]}:#{model.name.gsub ':', "\\:"}")) | |
| 181 | 181 | ActsAsSolr::Post.execute(Solr::Request::Commit.new) |
| 182 | 182 | end |
| 183 | 183 | ... | ... |
public/500.html
| ... | ... | @@ -55,13 +55,13 @@ |
| 55 | 55 | |
| 56 | 56 | |
| 57 | 57 | <div id='es' style='display: none' class='message'> |
| 58 | - <h1>Temporary system problem</h1> | |
| 58 | + <h1>Problema temporal del sistema</h1> | |
| 59 | 59 | <p> |
| 60 | - Our technical team is working on it, please try again later. Sorry for the inconvenience. | |
| 60 | + Nuestro equipo técnico está trabajando en ello, por favor, inténtalo de nuevo más tarde. Disculpa las molestias. | |
| 61 | 61 | </p> |
| 62 | 62 | <ul> |
| 63 | - <li><a href='javascript: history.back()'>Go back</a></li> | |
| 64 | - <li><a href='/'>Go to the site home page</a></li> | |
| 63 | + <li><a href='javascript: history.back()'>Regresar</a></li> | |
| 64 | + <li><a href='/'>Ir a la página de inicio del sitio</a></li> | |
| 65 | 65 | </ul> |
| 66 | 66 | </div> |
| 67 | 67 | |
| ... | ... | @@ -90,6 +90,18 @@ |
| 90 | 90 | </div> |
| 91 | 91 | |
| 92 | 92 | |
| 93 | + <div id='it' style='display: none' class='message'> | |
| 94 | + <h1>Temporary system problem</h1> | |
| 95 | + <p> | |
| 96 | + Our technical team is working on it, please try again later. Sorry for the inconvenience. | |
| 97 | + </p> | |
| 98 | + <ul> | |
| 99 | + <li><a href='javascript: history.back()'>Go back</a></li> | |
| 100 | + <li><a href='/'>Go to the site home page</a></li> | |
| 101 | + </ul> | |
| 102 | + </div> | |
| 103 | + | |
| 104 | + | |
| 93 | 105 | <div id='pt' style='display: none' class='message'> |
| 94 | 106 | <h1>Problema temporário no sistema</h1> |
| 95 | 107 | <p> |
| ... | ... | @@ -127,6 +139,8 @@ |
| 127 | 139 | |
| 128 | 140 | <a href="javascript: display_error_message('hy')">հայերեն լեզու</a> |
| 129 | 141 | |
| 142 | + <a href="javascript: display_error_message('it')">Italiano</a> | |
| 143 | + | |
| 130 | 144 | <a href="javascript: display_error_message('pt')">Português</a> |
| 131 | 145 | |
| 132 | 146 | <a href="javascript: display_error_message('ru')">русский язык</a> | ... | ... |
public/503.html
| ... | ... | @@ -43,9 +43,9 @@ |
| 43 | 43 | |
| 44 | 44 | |
| 45 | 45 | <div id='es' style='display: none' class='message'> |
| 46 | - <h1>System maintainance</h1> | |
| 46 | + <h1>Mantenimeinto del sistema</h1> | |
| 47 | 47 | <p> |
| 48 | - This system is under maintainance. It should be back in a few moments. | |
| 48 | + Este sistema está en mantenimiento. Debería regresar en unos momentos. | |
| 49 | 49 | </p> |
| 50 | 50 | </div> |
| 51 | 51 | |
| ... | ... | @@ -66,6 +66,14 @@ |
| 66 | 66 | </div> |
| 67 | 67 | |
| 68 | 68 | |
| 69 | + <div id='it' style='display: none' class='message'> | |
| 70 | + <h1>System maintainance</h1> | |
| 71 | + <p> | |
| 72 | + This system is under maintainance. It should be back in a few moments. | |
| 73 | + </p> | |
| 74 | + </div> | |
| 75 | + | |
| 76 | + | |
| 69 | 77 | <div id='pt' style='display: none' class='message'> |
| 70 | 78 | <h1>Manutenção do sistema</h1> |
| 71 | 79 | <p> |
| ... | ... | @@ -95,6 +103,8 @@ |
| 95 | 103 | |
| 96 | 104 | <a href="javascript: display_error_message('hy')">հայերեն լեզու</a> |
| 97 | 105 | |
| 106 | + <a href="javascript: display_error_message('it')">Italiano</a> | |
| 107 | + | |
| 98 | 108 | <a href="javascript: display_error_message('pt')">Português</a> |
| 99 | 109 | |
| 100 | 110 | <a href="javascript: display_error_message('ru')">русский язык</a> | ... | ... |
test/unit/location_block_test.rb
| ... | ... | @@ -29,11 +29,11 @@ class LocationBlockTest < ActiveSupport::TestCase |
| 29 | 29 | assert_equal '', LocationBlock.new.title |
| 30 | 30 | end |
| 31 | 31 | |
| 32 | - should 'use google maps api v3' do | |
| 32 | + should 'use google maps api v3 with ssl' do | |
| 33 | 33 | @block.owner.lat = '-12.34'; @block.owner.save! |
| 34 | 34 | content = extract_block_content(@block.content) |
| 35 | 35 | |
| 36 | - assert_match 'http://maps.google.com/maps/api/staticmap', content | |
| 36 | + assert_match 'https://maps.google.com/maps/api/staticmap', content | |
| 37 | 37 | assert_no_match /key=/, content |
| 38 | 38 | end |
| 39 | 39 | ... | ... |
test/unit/profile_test.rb
| ... | ... | @@ -1379,6 +1379,16 @@ class ProfileTest < ActiveSupport::TestCase |
| 1379 | 1379 | assert_not_includes Profile.templates(Environment.default), profile |
| 1380 | 1380 | end |
| 1381 | 1381 | |
| 1382 | + should 'not crash on a profile update with a destroyed template' do | |
| 1383 | + template = fast_create(Profile, :is_template => true) | |
| 1384 | + profile = fast_create(Profile, :template_id => template.id) | |
| 1385 | + template.destroy | |
| 1386 | + | |
| 1387 | + assert_nothing_raised do | |
| 1388 | + Profile.find(profile.id).save! | |
| 1389 | + end | |
| 1390 | + end | |
| 1391 | + | |
| 1382 | 1392 | should 'provide URL to leave' do |
| 1383 | 1393 | profile = build(Profile, :identifier => 'testprofile') |
| 1384 | 1394 | assert_equal({ :profile => 'testprofile', :controller => 'profile', :action => 'leave', :reload => false}, profile.leave_url) | ... | ... |
vendor/plugins/delayed_job/lib/delayed/worker.rb
| ... | ... | @@ -10,12 +10,12 @@ module Delayed |
| 10 | 10 | self.max_attempts = 25 |
| 11 | 11 | self.max_run_time = 4.hours |
| 12 | 12 | self.default_priority = 0 |
| 13 | - | |
| 13 | + | |
| 14 | 14 | # By default failed jobs are destroyed after too many attempts. If you want to keep them around |
| 15 | 15 | # (perhaps to inspect the reason for the failure), set this to false. |
| 16 | 16 | cattr_accessor :destroy_failed_jobs |
| 17 | 17 | self.destroy_failed_jobs = true |
| 18 | - | |
| 18 | + | |
| 19 | 19 | self.logger = if defined?(Merb::Logger) |
| 20 | 20 | Merb.logger |
| 21 | 21 | elsif defined?(RAILS_DEFAULT_LOGGER) |
| ... | ... | @@ -24,9 +24,9 @@ module Delayed |
| 24 | 24 | |
| 25 | 25 | # name_prefix is ignored if name is set directly |
| 26 | 26 | attr_accessor :name_prefix |
| 27 | - | |
| 27 | + | |
| 28 | 28 | cattr_reader :backend |
| 29 | - | |
| 29 | + | |
| 30 | 30 | def self.backend=(backend) |
| 31 | 31 | if backend.is_a? Symbol |
| 32 | 32 | require "delayed/backend/#{backend}" |
| ... | ... | @@ -35,7 +35,7 @@ module Delayed |
| 35 | 35 | @@backend = backend |
| 36 | 36 | silence_warnings { ::Delayed.const_set(:Job, backend) } |
| 37 | 37 | end |
| 38 | - | |
| 38 | + | |
| 39 | 39 | def self.guess_backend |
| 40 | 40 | self.backend ||= if defined?(ActiveRecord) |
| 41 | 41 | :active_record |
| ... | ... | @@ -97,7 +97,7 @@ module Delayed |
| 97 | 97 | ensure |
| 98 | 98 | Delayed::Job.clear_locks!(name) |
| 99 | 99 | end |
| 100 | - | |
| 100 | + | |
| 101 | 101 | # Do num jobs and return stats on success/failure. |
| 102 | 102 | # Exit early if interrupted. |
| 103 | 103 | def work_off(num = 100) |
| ... | ... | @@ -117,7 +117,7 @@ module Delayed |
| 117 | 117 | |
| 118 | 118 | return [success, failure] |
| 119 | 119 | end |
| 120 | - | |
| 120 | + | |
| 121 | 121 | def run(job) |
| 122 | 122 | runtime = Benchmark.realtime do |
| 123 | 123 | Timeout.timeout(self.class.max_run_time.to_i) { job.invoke_job } |
| ... | ... | @@ -129,7 +129,7 @@ module Delayed |
| 129 | 129 | handle_failed_job(job, e) |
| 130 | 130 | return false # work failed |
| 131 | 131 | end |
| 132 | - | |
| 132 | + | |
| 133 | 133 | # Reschedule the job in the future (when a job fails). |
| 134 | 134 | # Uses an exponential scale depending on the number of failed attempts. |
| 135 | 135 | def reschedule(job, time = nil) |
| ... | ... | @@ -162,13 +162,13 @@ module Delayed |
| 162 | 162 | end |
| 163 | 163 | |
| 164 | 164 | protected |
| 165 | - | |
| 165 | + | |
| 166 | 166 | def handle_failed_job(job, error) |
| 167 | 167 | job.last_error = error.message + "\n" + error.backtrace.join("\n") |
| 168 | 168 | say "#{job.name} failed with #{error.class.name}: #{error.message} - #{job.attempts} failed attempts", Logger::ERROR |
| 169 | 169 | reschedule(job) |
| 170 | 170 | end |
| 171 | - | |
| 171 | + | |
| 172 | 172 | # Run the next job we can get an exclusive lock on. |
| 173 | 173 | # If no jobs are left we return nil |
| 174 | 174 | def reserve_and_run_one_job | ... | ... |
vendor/plugins/monkey_patches/rescue_delayed_job_crashes/init.rb
0 → 100644
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +Delayed::Worker.module_eval do | |
| 2 | + # based on https://groups.google.com/forum/#!topic/delayed_job/ZGMUFFppNgs | |
| 3 | + class Delayed::Worker::ExceptionNotification < ActionMailer::Base | |
| 4 | + def mail error | |
| 5 | + environment = Environment.default | |
| 6 | + | |
| 7 | + recipients NOOSFERO_CONF['exception_recipients'] | |
| 8 | + from environment.contact_email | |
| 9 | + reply_to environment.contact_email | |
| 10 | + subject "[#{environment.name}] DelayedJob: #{error.message}" | |
| 11 | + body render(:text => error.backtrace.join("\n")) | |
| 12 | + end | |
| 13 | + end | |
| 14 | + | |
| 15 | + def handle_failed_job_with_notification(job, error) | |
| 16 | + Delayed::Worker::ExceptionNotification.deliver_mail error if NOOSFERO_CONF['exception_recipients'].present? | |
| 17 | + handle_failed_job_without_notification job, error | |
| 18 | + end | |
| 19 | + alias_method_chain :handle_failed_job, :notification | |
| 20 | + | |
| 21 | + def handle_failed_job_with_rescue(job, error) | |
| 22 | + handle_failed_job_without_rescue(job, error) | |
| 23 | + rescue => e # don't crash here | |
| 24 | + end | |
| 25 | + alias_method_chain :handle_failed_job, :rescue | |
| 26 | + | |
| 27 | + protected | |
| 28 | + | |
| 29 | + # This code must be replicated because there is no other way to pass the job | |
| 30 | + # through and use alias_method_chain as we used on the previous method | |
| 31 | + def reserve_and_run_one_job | |
| 32 | + # We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next. | |
| 33 | + # this leads to a more even distribution of jobs across the worker processes | |
| 34 | + job = Delayed::Job.find_available(name, 5, self.class.max_run_time).detect do |job| | |
| 35 | + if job.lock_exclusively!(self.class.max_run_time, name) | |
| 36 | + say "acquired lock on #{job.name}" | |
| 37 | + true | |
| 38 | + else | |
| 39 | + say "failed to acquire exclusive lock for #{job.name}", Logger::WARN | |
| 40 | + false | |
| 41 | + end | |
| 42 | + end | |
| 43 | + | |
| 44 | + run(job) if job | |
| 45 | + rescue => e | |
| 46 | + handle_failed_job(job, e) | |
| 47 | + end | |
| 48 | +end | ... | ... |