diff --git a/app/Services/Dns/HttpHetznerDnsClient.php b/app/Services/Dns/HttpHetznerDnsClient.php index 21506f9..c9d7807 100644 --- a/app/Services/Dns/HttpHetznerDnsClient.php +++ b/app/Services/Dns/HttpHetznerDnsClient.php @@ -50,6 +50,15 @@ class HttpHetznerDnsClient implements HetznerDnsClient public function deleteRecord(string $recordId): void { - $this->http()->delete("/records/{$recordId}")->throw(); + $response = $this->http()->delete("/records/{$recordId}"); + + // A record that is already gone is the outcome we wanted. Without this, + // a lost response or a retry after a later failure turns every further + // attempt into a 404 — and a host that can then never be purged. + if ($response->notFound()) { + return; + } + + $response->throw(); } } diff --git a/tests/Feature/Provisioning/ServicesTest.php b/tests/Feature/Provisioning/ServicesTest.php index 3c0e67a..70d8883 100644 --- a/tests/Feature/Provisioning/ServicesTest.php +++ b/tests/Feature/Provisioning/ServicesTest.php @@ -103,3 +103,13 @@ it('reports node capacity for a host (FakeProxmoxClient)', function () { ->and($client->nodeStatus('pve')['memory']['total'])->toBeGreaterThan(0) ->and($client->nodeStorage('pve')[0]['total'])->toBeGreaterThan(0); }); + +it('treats an already-deleted DNS record as done', function () { + Illuminate\Support\Facades\Http::fake([ + '*' => Illuminate\Support\Facades\Http::response(['error' => 'not found'], 404), + ]); + + // A lost response, or a retry after a later step failed, must not make the + // record impossible to clean up — and its host impossible to purge. + (new App\Services\Dns\HttpHetznerDnsClient)->deleteRecord('rec-123'); +})->throwsNoExceptions();