mirror of https://github.com/pixelfed/pixelfed
Merge pull request #7514 from pixelfed/fix/nodeinfo-delivery-cooldown-columns
Give Nodeinfo crawler its own cooldown columns, separate from deliverypull/7522/head
commit
2a5c8f45ec
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Nodeinfo crawling reused the ActivityPub delivery-backoff columns
|
||||
// (delivery_timeout / delivery_next_after), so a failed Nodeinfo fetch
|
||||
// could mark a sub-threshold host unavailable for delivery. Give the
|
||||
// Nodeinfo crawler its own cooldown columns.
|
||||
Schema::table('instances', function (Blueprint $table) {
|
||||
if (! Schema::hasColumn('instances', 'nodeinfo_timeout')) {
|
||||
$table->boolean('nodeinfo_timeout')->default(false);
|
||||
}
|
||||
|
||||
if (! Schema::hasColumn('instances', 'nodeinfo_next_after')) {
|
||||
$table->timestamp('nodeinfo_next_after')->nullable();
|
||||
}
|
||||
});
|
||||
|
||||
// Backfill: any host below the delivery failure threshold should not be
|
||||
// carrying a delivery backoff. Nodeinfo failures previously wrote these
|
||||
// columns without touching delivery_failures, so clear that stale state
|
||||
// (applyFailure() re-arms it on the next threshold-crossing failure).
|
||||
$threshold = max(1, (int) config('federation.activitypub.delivery.failure_threshold', 5));
|
||||
|
||||
DB::table('instances')
|
||||
->where('delivery_failures', '<', $threshold)
|
||||
->update([
|
||||
'delivery_timeout' => false,
|
||||
'delivery_next_after' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('instances', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('instances', 'nodeinfo_next_after')) {
|
||||
$table->dropColumn('nodeinfo_next_after');
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('instances', 'nodeinfo_timeout')) {
|
||||
$table->dropColumn('nodeinfo_timeout');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
use App\Jobs\InstancePipeline\FetchNodeinfoPipeline;
|
||||
use App\Models\Instance;
|
||||
use App\Services\DeliveryHostService;
|
||||
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
uses(LazilyRefreshDatabase::class);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Nodeinfo cooldown must not touch the ActivityPub delivery-backoff columns
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| FetchNodeinfoPipeline reused delivery_timeout / delivery_next_after, so a
|
||||
| Nodeinfo failure marked a sub-threshold host unavailable for AP delivery
|
||||
| for 14h. Nodeinfo now owns nodeinfo_timeout / nodeinfo_next_after; the
|
||||
| delivery columns are written only by DeliveryHostService.
|
||||
|
|
||||
*/
|
||||
|
||||
beforeEach(function () {
|
||||
config(['federation.activitypub.delivery.failure_threshold' => 5]);
|
||||
Http::fake(['*' => Http::response('', 404)]); // force the Nodeinfo failure branch
|
||||
DeliveryHostService::reset('sub.example');
|
||||
});
|
||||
|
||||
it('writes nodeinfo cooldown columns and leaves delivery columns untouched on failure', function () {
|
||||
$instance = new Instance;
|
||||
$instance->domain = 'sub.example';
|
||||
$instance->delivery_failures = 1;
|
||||
$instance->delivery_timeout = false;
|
||||
$instance->delivery_next_after = null;
|
||||
$instance->save();
|
||||
|
||||
(new FetchNodeinfoPipeline($instance))->handle();
|
||||
|
||||
$instance->refresh();
|
||||
|
||||
// Nodeinfo cooldown armed on its own columns.
|
||||
expect((bool) $instance->nodeinfo_timeout)->toBeTrue();
|
||||
expect($instance->nodeinfo_next_after)->not->toBeNull();
|
||||
|
||||
// Delivery-backoff columns untouched by the Nodeinfo crawl.
|
||||
expect((bool) $instance->delivery_timeout)->toBeFalse();
|
||||
expect($instance->delivery_next_after)->toBeNull();
|
||||
});
|
||||
|
||||
it('does not report a sub-threshold host unavailable after a nodeinfo failure', function () {
|
||||
$instance = new Instance;
|
||||
$instance->domain = 'sub.example';
|
||||
$instance->delivery_failures = 1; // well under threshold of 5
|
||||
$instance->delivery_timeout = false;
|
||||
$instance->delivery_next_after = null;
|
||||
$instance->save();
|
||||
|
||||
(new FetchNodeinfoPipeline($instance))->handle();
|
||||
|
||||
// The AP delivery layer must still consider the host available.
|
||||
expect(DeliveryHostService::isUnavailable('sub.example'))->toBeFalse();
|
||||
});
|
||||
Loading…
Reference in New Issue