New task checking if remote instance is reachable to avoid playback latence
This commit is contained in:
parent
4ae9d77cf2
commit
0cb3457378
|
@ -862,6 +862,16 @@ CELERY_BEAT_SCHEDULE = {
|
||||||
"schedule": crontab(day_of_week="1", minute="0", hour="2"),
|
"schedule": crontab(day_of_week="1", minute="0", hour="2"),
|
||||||
"options": {"expires": 60 * 60 * 24},
|
"options": {"expires": 60 * 60 * 24},
|
||||||
},
|
},
|
||||||
|
"federation.check_remote_instance_availability": {
|
||||||
|
"task": "federation.check_remote_instance_availability",
|
||||||
|
"schedule": crontab(
|
||||||
|
**env.dict(
|
||||||
|
"SCHEDULE_FEDERATION_CHECK_INTANCES_AVAILABILITY",
|
||||||
|
default={"minute": "0", "hour": "*"},
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"options": {"expires": 60 * 60},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if env.bool("ADD_ALBUM_TAGS_FROM_TRACKS", default=True):
|
if env.bool("ADD_ALBUM_TAGS_FROM_TRACKS", default=True):
|
||||||
|
|
|
@ -70,6 +70,8 @@ class DomainFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
||||||
name = factory.Faker("domain_name")
|
name = factory.Faker("domain_name")
|
||||||
nodeinfo_fetch_date = factory.LazyFunction(lambda: timezone.now())
|
nodeinfo_fetch_date = factory.LazyFunction(lambda: timezone.now())
|
||||||
allowed = None
|
allowed = None
|
||||||
|
reachable = True
|
||||||
|
last_successful_contact = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = "federation.Domain"
|
model = "federation.Domain"
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.16 on 2022-10-27 11:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('federation', '0027_auto_20220627_1915'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='domain',
|
||||||
|
name='last_successful_contact',
|
||||||
|
field=models.DateTimeField(default=None, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='domain',
|
||||||
|
name='reachable',
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -123,7 +123,8 @@ class Domain(models.Model):
|
||||||
)
|
)
|
||||||
# are interactions with this domain allowed (only applies when allow-listing is on)
|
# are interactions with this domain allowed (only applies when allow-listing is on)
|
||||||
allowed = models.BooleanField(default=None, null=True)
|
allowed = models.BooleanField(default=None, null=True)
|
||||||
|
reachable = models.BooleanField(default=True)
|
||||||
|
last_successful_contact = models.DateTimeField(default=None, null=True)
|
||||||
objects = DomainQuerySet.as_manager()
|
objects = DomainQuerySet.as_manager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
@ -625,3 +625,35 @@ def fetch_collection(url, max_pages, channel, is_page=False):
|
||||||
results["errored"],
|
results["errored"],
|
||||||
)
|
)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
@celery.app.task(name="federation.check_all_remote_instance_availability")
|
||||||
|
def check_all_remote_instance_availability():
|
||||||
|
domains = models.Domain.objects.all().prefetch_related()
|
||||||
|
for domain in domains:
|
||||||
|
check_single_remote_instance_availability(domain)
|
||||||
|
|
||||||
|
|
||||||
|
@celery.app.task(name="federation.check_single_remote_instance_availability")
|
||||||
|
def check_single_remote_instance_availability(domain):
|
||||||
|
try:
|
||||||
|
response = requests.get(f"https://{domain.name}/api/v1/instance/nodeinfo/2.0/")
|
||||||
|
nodeinfo = response.json()
|
||||||
|
except Exception as e:
|
||||||
|
logger.info(
|
||||||
|
f"Domain {domain.name} could not be reached because of the following error : {e}. \
|
||||||
|
Setting domain as unreacheable."
|
||||||
|
)
|
||||||
|
domain.reachable = False
|
||||||
|
domain.save()
|
||||||
|
|
||||||
|
if "version" in nodeinfo.keys():
|
||||||
|
domain.reachable = True
|
||||||
|
domain.last_successful_contact = datetime.datetime.now()
|
||||||
|
domain.save()
|
||||||
|
else:
|
||||||
|
logger.info(
|
||||||
|
f"Domain {domain.name} is not reacheable at the moment. Setting domain as unreacheable."
|
||||||
|
)
|
||||||
|
domain.reachable = False
|
||||||
|
domain.save()
|
||||||
|
|
|
@ -1184,12 +1184,15 @@ class LibraryQuerySet(models.QuerySet):
|
||||||
)
|
)
|
||||||
.values_list("target__channel__library", flat=True)
|
.values_list("target__channel__library", flat=True)
|
||||||
)
|
)
|
||||||
|
domains_reachable = federation_models.Domain.objects.filter(reachable=True)
|
||||||
|
|
||||||
return self.filter(
|
return self.filter(
|
||||||
me_query
|
me_query
|
||||||
| instance_query
|
| instance_query
|
||||||
| models.Q(privacy_level="everyone")
|
| models.Q(privacy_level="everyone")
|
||||||
| models.Q(pk__in=followed_libraries)
|
| models.Q(pk__in=followed_libraries)
|
||||||
| models.Q(pk__in=followed_channels_libraries)
|
| models.Q(pk__in=followed_channels_libraries)
|
||||||
|
& models.Q(actor__domain__in=domains_reachable)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -670,3 +670,22 @@ def test_fetch_collection(mocker, r_mock):
|
||||||
assert result["seen"] == 7
|
assert result["seen"] == 7
|
||||||
assert result["total"] == 27094
|
assert result["total"] == 27094
|
||||||
assert result["next_page"] == payloads["page2"]["next"]
|
assert result["next_page"] == payloads["page2"]["next"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_all_remote_instance_reachable(factories, r_mock):
|
||||||
|
domain = factories["federation.Domain"]()
|
||||||
|
r_mock.get(
|
||||||
|
f"https://{domain.name}/api/v1/instance/nodeinfo/2.0/", json={"version": "2"}
|
||||||
|
)
|
||||||
|
tasks.check_all_remote_instance_availability()
|
||||||
|
domain = models.Domain.objects.get(name=domain.name)
|
||||||
|
assert domain.reachable is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_check_remote_instance_unreachable(factories, r_mock):
|
||||||
|
domain = factories["federation.Domain"]()
|
||||||
|
|
||||||
|
r_mock.get(f"https://{domain.name}/api/v1/instance/nodeinfo/2.0/", json={})
|
||||||
|
tasks.check_all_remote_instance_availability()
|
||||||
|
domain = models.Domain.objects.get(name=domain.name)
|
||||||
|
assert domain.reachable is False
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
New task checking if remote instance is reachable to avoid playback latence (#1711)
|
Loading…
Reference in New Issue