diff --git a/Changelog.md b/Changelog.md index 591dd24bf..8765280d5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -44,6 +44,7 @@ Note: Although this is a minor release, the configuration file changed because t * You'll now get redirected to the invites page if you follow an invitation but you're already logged inĀ [#7061](https://github.com/diaspora/diaspora/pull/7061) * Add support for setting BOSH access protocol via chat configuration [#7100](https://github.com/diaspora/diaspora/pull/7100) * Add number of unreviewed reports to admin dashboard and admin sidebar [#7109](https://github.com/diaspora/diaspora/pull/7109) +* Don't federate to pods that have been offline for an extended period of time [#7120](https://github.com/diaspora/diaspora/pull/7120) # 0.6.0.1 diff --git a/app/models/pod.rb b/app/models/pod.rb index a42456622..031566433 100644 --- a/app/models/pod.rb +++ b/app/models/pod.rb @@ -66,8 +66,13 @@ class Pod < ActiveRecord::Base Pod.offline_statuses.include?(Pod.statuses[status]) end - def was_offline? - Pod.offline_statuses.include?(Pod.statuses[status_was]) + # a pod is active if it is online or was online less than 14 days ago + def active? + !offline? || offline_since.try {|date| date > DateTime.now.utc - 14.days } + end + + def to_s + "#{id}:#{host}" end def test_connection! @@ -87,7 +92,7 @@ class Pod < ActiveRecord::Base def update_offline_since if offline? - touch(:offline_since) unless was_offline? + self.offline_since ||= DateTime.now.utc else self.offline_since = nil end diff --git a/lib/diaspora/federation/dispatcher/private.rb b/lib/diaspora/federation/dispatcher/private.rb index c959dd3b6..ab13756fd 100644 --- a/lib/diaspora/federation/dispatcher/private.rb +++ b/lib/diaspora/federation/dispatcher/private.rb @@ -12,7 +12,9 @@ module Diaspora end def targets(people, salmon_slap) - people.map {|person| [person.receive_url, salmon_slap.generate_xml(person.public_key)] }.to_h + active, inactive = people.partition {|person| person.pod.active? } + logger.info "ignoring inactive pods: #{inactive.map(&:diaspora_handle).join(', ')}" if inactive.any? + active.map {|person| [person.receive_url, salmon_slap.generate_xml(person.public_key)] }.to_h end def salmon_slap(entity) diff --git a/lib/diaspora/federation/dispatcher/public.rb b/lib/diaspora/federation/dispatcher/public.rb index c063ed118..c91979c20 100644 --- a/lib/diaspora/federation/dispatcher/public.rb +++ b/lib/diaspora/federation/dispatcher/public.rb @@ -19,7 +19,9 @@ module Diaspora end def target_urls(people) - Pod.where(id: people.map(&:pod_id).uniq).map {|pod| pod.url_to("/receive/public") } + active, inactive = Pod.where(id: people.map(&:pod_id).uniq).partition(&:active?) + logger.info "ignoring inactive pods: #{inactive.join(', ')}" if inactive.any? + active.map {|pod| pod.url_to("/receive/public") } end def additional_target_urls diff --git a/spec/lib/diaspora/federation/dispatcher/private_spec.rb b/spec/lib/diaspora/federation/dispatcher/private_spec.rb index 43eb2e895..b70d7996d 100644 --- a/spec/lib/diaspora/federation/dispatcher/private_spec.rb +++ b/spec/lib/diaspora/federation/dispatcher/private_spec.rb @@ -71,6 +71,25 @@ describe Diaspora::Federation::Dispatcher::Private do Diaspora::Federation::Dispatcher.build(alice, post, subscribers: [remote_person]).dispatch end + + it "only queues a private send job for a active pods" do + remote_person = FactoryGirl.create(:person) + offline_pod = FactoryGirl.create(:pod, status: :net_failed, offline_since: DateTime.now.utc - 15.days) + offline_person = FactoryGirl.create(:person, pod: offline_pod) + + expect(Workers::SendPrivate).to receive(:perform_async) do |user_id, _entity_string, targets| + expect(user_id).to eq(alice.id) + expect(targets.size).to eq(1) + expect(targets).to have_key(remote_person.receive_url) + expect(targets[remote_person.receive_url]).to eq(xml) + end + + salmon = double + expect(DiasporaFederation::Salmon::EncryptedSlap).to receive(:prepare).and_return(salmon) + expect(salmon).to receive(:generate_xml).and_return(xml) + + Diaspora::Federation::Dispatcher.build(alice, post, subscribers: [remote_person, offline_person]).dispatch + end end end diff --git a/spec/lib/diaspora/federation/dispatcher/public_spec.rb b/spec/lib/diaspora/federation/dispatcher/public_spec.rb index 5fb654f02..20c144ea6 100644 --- a/spec/lib/diaspora/federation/dispatcher/public_spec.rb +++ b/spec/lib/diaspora/federation/dispatcher/public_spec.rb @@ -67,7 +67,7 @@ describe Diaspora::Federation::Dispatcher::Public do Diaspora::Federation::Dispatcher.build(alice, post).dispatch end - it "does not queue a private send job when no remote recipients specified" do + it "does not queue a public send job when no remote recipients specified" do expect(Workers::SendPublic).not_to receive(:perform_async) Diaspora::Federation::Dispatcher.build(alice, post).dispatch @@ -85,6 +85,22 @@ describe Diaspora::Federation::Dispatcher::Public do Diaspora::Federation::Dispatcher.build(alice, post, subscribers: [remote_raphael]).dispatch end + + it "only queues a public send job for a active pods" do + offline_pod = FactoryGirl.create(:pod, status: :net_failed, offline_since: DateTime.now.utc - 15.days) + offline_person = FactoryGirl.create(:person, pod: offline_pod) + + expect(Workers::SendPublic).to receive(:perform_async) do |user_id, _entity_string, urls, xml| + expect(user_id).to eq(alice.id) + expect(urls.size).to eq(1) + expect(urls[0]).to eq(remote_raphael.pod.url_to("/receive/public")) + expect(xml).to eq(salmon_xml) + end + + expect(DiasporaFederation::Salmon::Slap).to receive(:generate_xml).and_return(salmon_xml) + + Diaspora::Federation::Dispatcher.build(alice, post, subscribers: [remote_raphael, offline_person]).dispatch + end end end diff --git a/spec/models/pod_spec.rb b/spec/models/pod_spec.rb index 1624b562b..beb283414 100644 --- a/spec/models/pod_spec.rb +++ b/spec/models/pod_spec.rb @@ -82,6 +82,28 @@ describe Pod, type: :model do end end + describe "#active?" do + it "returns true for an unchecked pod" do + pod = FactoryGirl.create(:pod) + expect(pod.active?).to be_truthy + end + + it "returns true for an online pod" do + pod = FactoryGirl.create(:pod, status: :no_errors) + expect(pod.reload.active?).to be_truthy + end + + it "returns true for a pod that is offline for less than 14 days" do + pod = FactoryGirl.create(:pod, status: :net_failed, offline_since: DateTime.now.utc - 13.days) + expect(pod.active?).to be_truthy + end + + it "returns false for a pod that is offline for less than 14 days" do + pod = FactoryGirl.create(:pod, status: :net_failed, offline_since: DateTime.now.utc - 15.days) + expect(pod.active?).to be_falsey + end + end + describe "#test_connection!" do before do @pod = FactoryGirl.create(:pod)