mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(domains): stop the DNS poll from flooding the high queue
The Domains page polls every 2 seconds while a DNS check runs. Each poll parsed the compose file, and the parser queued one ServerFilesFromServerJob per volume. The jobs starved the DNS check jobs and deployments. - Skip the compose parse in pollDnsChecks and keep the known services. - Make ServerFilesFromServerJob unique per resource until it runs. Fixes #12098
This commit is contained in:
@@ -7,20 +7,32 @@ use App\Models\ServiceApplication;
|
||||
use App\Models\ServiceDatabase;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ServerFilesFromServerJob implements ShouldBeEncrypted, ShouldQueue
|
||||
class ServerFilesFromServerJob implements ShouldBeEncrypted, ShouldBeUniqueUntilProcessing, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
/**
|
||||
* Only one sync per resource can wait in the queue. The compose parser dispatches
|
||||
* this job once per volume on every parse, so without this the queue fills with copies.
|
||||
*/
|
||||
public int $uniqueFor = 600;
|
||||
|
||||
public function __construct(public ServiceApplication|ServiceDatabase|Application $resource)
|
||||
{
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return $this->resource::class.':'.$this->resource->id;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$this->resource->getFilesFromServer(isInit: true);
|
||||
|
||||
@@ -178,11 +178,11 @@ class Domains extends Component
|
||||
$this->loadDomainState();
|
||||
}
|
||||
|
||||
public function refreshDomains(): void
|
||||
public function refreshDomains(bool $parseCompose = true): void
|
||||
{
|
||||
$editingRow = $this->editingIndex !== null ? ($this->domainRows[$this->editingIndex] ?? null) : null;
|
||||
|
||||
$this->loadDomainState();
|
||||
$this->loadDomainState($parseCompose);
|
||||
|
||||
if ($editingRow !== null) {
|
||||
$index = collect($this->domainRows)->search(fn (array $row): bool => $row['url'] === $editingRow['url']
|
||||
@@ -199,7 +199,9 @@ class Domains extends Component
|
||||
->where('dns_status', 'checking')
|
||||
->values();
|
||||
|
||||
$this->refreshDomains();
|
||||
// The poll only refreshes DNS results. Parsing the compose file here would
|
||||
// queue file sync jobs on every tick and starve the DNS check jobs.
|
||||
$this->refreshDomains(parseCompose: false);
|
||||
|
||||
foreach ($checkingRows as $checkingRow) {
|
||||
$row = collect($this->domainRows)->first(fn (array $row): bool => $row['url'] === $checkingRow['url']
|
||||
@@ -258,7 +260,7 @@ class Domains extends Component
|
||||
$this->dispatch('success', 'HTTP to HTTPS redirect updated.');
|
||||
}
|
||||
|
||||
public function loadDomainState(): void
|
||||
public function loadDomainState(bool $parseCompose = true): void
|
||||
{
|
||||
$this->application->refresh();
|
||||
$this->application->loadMissing(['destination.server', 'settings', 'additional_servers']);
|
||||
@@ -293,23 +295,27 @@ class Domains extends Component
|
||||
$this->serverIpConfigured = null;
|
||||
}
|
||||
|
||||
$this->composeServices = [];
|
||||
$pendingRedirect = $this->pendingRedirectService !== null
|
||||
? ($this->serviceRedirects[$this->serviceRedirectWireKey($this->pendingRedirectService)] ?? null)
|
||||
: null;
|
||||
$this->serviceRedirects = [];
|
||||
if ($this->isCompose) {
|
||||
if (! $this->isCompose) {
|
||||
$this->composeServices = [];
|
||||
} elseif ($parseCompose) {
|
||||
try {
|
||||
$parsed = $this->application->parse() ?? [];
|
||||
} catch (\Throwable) {
|
||||
$parsed = [];
|
||||
}
|
||||
$this->composeServices = [];
|
||||
$services = data_get($parsed, 'services', []);
|
||||
foreach ($services as $serviceName => $service) {
|
||||
if (! isDatabaseImage(data_get($service, 'image'))) {
|
||||
$this->composeServices[] = $serviceName;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->isCompose) {
|
||||
if ($this->newDomainService === null && count($this->composeServices) > 0) {
|
||||
$this->newDomainService = $this->composeServices[0];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use App\Jobs\CheckDomainDnsJob;
|
||||
use App\Jobs\ConfigureDnsRecordJob;
|
||||
use App\Jobs\ServerFilesFromServerJob;
|
||||
use App\Livewire\Project\Application\Domains;
|
||||
use App\Livewire\Project\Application\PreviewDomains;
|
||||
use App\Livewire\Project\Application\Previews;
|
||||
@@ -3656,3 +3657,25 @@ it('offers dns provider record creation for a public server ip', function () {
|
||||
->toContain('Add with Cloudflare')
|
||||
->not->toContain('The server has no public IP address; add the DNS record manually.');
|
||||
});
|
||||
|
||||
it('does not queue file sync jobs when polling dns checks for compose applications', function () {
|
||||
Queue::fake();
|
||||
|
||||
$this->application->update([
|
||||
'build_pack' => 'dockercompose',
|
||||
'docker_compose_raw' => "services:\n web:\n image: nginx:alpine\n volumes:\n - web-data:/data\n api:\n image: nginx:alpine\n volumes:\n - api-data:/data\n - api-conf:/etc/api\nvolumes:\n web-data:\n api-data:\n api-conf:\n",
|
||||
'docker_compose_domains' => json_encode([
|
||||
'web' => ['domain' => 'https://compose-poll-test.invalid'],
|
||||
]),
|
||||
'fqdn' => null,
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Domains::class, ['application' => $this->application->fresh()]);
|
||||
$queuedOnMount = Queue::pushed(ServerFilesFromServerJob::class)->count();
|
||||
|
||||
$component->call('pollDnsChecks')->call('pollDnsChecks')->call('pollDnsChecks');
|
||||
|
||||
expect($queuedOnMount)->toBe(1)
|
||||
->and(Queue::pushed(ServerFilesFromServerJob::class))->toHaveCount(1)
|
||||
->and($component->get('composeServices'))->toBe(['web', 'api']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user