Instead of rebuilding the entire scheduler queue, incrementally add or remove jobs when domains are created/deleted or zones are imported/published. A wake channel interrupts the run loop so new jobs are picked up immediately. A jobKeys index prevents duplicate entries. Hook points: domain creation, domain deletion, zone import, and zone publish (correction apply) all notify the scheduler via the narrow SchedulerDomainNotifier interface, wired through setter methods to avoid initialization ordering issues.
100 lines
4.5 KiB
Go
100 lines
4.5 KiB
Go
// This file is part of the happyDomain (R) project.
|
|
// Copyright (c) 2020-2025 happyDomain
|
|
// Authors: Pierre-Olivier Mercier, et al.
|
|
//
|
|
// This program is offered under a commercial and under the AGPL license.
|
|
// For commercial licensing, contact us at <contact@happydomain.org>.
|
|
//
|
|
// For AGPL licensing:
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
// Package orchestrator wires together lower-level use-cases to implement the
|
|
// multi-step workflows that span provider access, zone storage, and domain
|
|
// history management. It sits between the HTTP/API layer and the individual
|
|
// domain/zone use-cases, coordinating the sequence of operations required to
|
|
// import, diff, and publish DNS zones.
|
|
package orchestrator
|
|
|
|
import (
|
|
"context"
|
|
|
|
domainlogUC "git.happydns.org/happyDomain/internal/usecase/domain_log"
|
|
zoneUC "git.happydns.org/happyDomain/internal/usecase/zone"
|
|
"git.happydns.org/happyDomain/model"
|
|
)
|
|
|
|
// DomainUpdater is an interface for updating domains.
|
|
type DomainUpdater interface {
|
|
Update(domainID happydns.Identifier, user *happydns.User, updateFn func(*happydns.Domain)) error
|
|
}
|
|
|
|
// ProviderGetter is an interface for getting providers.
|
|
type ProviderGetter interface {
|
|
GetUserProvider(ctx context.Context, user *happydns.User, providerID happydns.Identifier) (*happydns.Provider, error)
|
|
}
|
|
|
|
// ZoneRetriever is an interface for retrieving zones from providers.
|
|
type ZoneRetriever interface {
|
|
RetrieveZone(ctx context.Context, provider *happydns.Provider, name string) ([]happydns.Record, error)
|
|
}
|
|
|
|
// ZoneCorrector is an interface for getting zone corrections.
|
|
type ZoneCorrector interface {
|
|
ListZoneCorrections(ctx context.Context, provider *happydns.Provider, domain *happydns.Domain, records []happydns.Record) ([]*happydns.Correction, int, error)
|
|
}
|
|
|
|
// Orchestrator aggregates the use-cases that together implement the DNS zone
|
|
// lifecycle: importing zones from a provider, listing required corrections, and
|
|
// applying those corrections back to the provider.
|
|
type Orchestrator struct {
|
|
// RemoteZoneImporter fetches a live zone from the provider and stores it.
|
|
RemoteZoneImporter *RemoteZoneImporterUsecase
|
|
// ZoneCorrectionApplier lists and applies the corrections needed to bring
|
|
// the provider in sync with the desired zone state.
|
|
ZoneCorrectionApplier *ZoneCorrectionApplierUsecase
|
|
// ZoneImporter converts a flat list of DNS records into a happyDomain zone
|
|
// and persists it in the domain history.
|
|
ZoneImporter *ZoneImporterUsecase
|
|
}
|
|
|
|
// NewOrchestrator constructs an Orchestrator by wiring up all required
|
|
// dependencies. It builds the shared ZoneImporterUsecase and
|
|
// ZoneCorrectionListerUsecase internally so callers do not need to manage
|
|
// those intermediate objects.
|
|
func NewOrchestrator(
|
|
appendDomainLog domainlogUC.DomainLogAppender,
|
|
domainUpdater DomainUpdater,
|
|
providerService ProviderGetter,
|
|
listRecords *zoneUC.ListRecordsUsecase,
|
|
zoneCorrectorService ZoneCorrector,
|
|
zoneCreator *zoneUC.CreateZoneUsecase,
|
|
zoneGetter *zoneUC.GetZoneUsecase,
|
|
zoneRetrieverService ZoneRetriever,
|
|
zoneUpdater *zoneUC.UpdateZoneUsecase,
|
|
) *Orchestrator {
|
|
zoneImporter := NewZoneImporterUsecase(domainUpdater, zoneCreator, zoneGetter)
|
|
zoneCorrectionLister := NewZoneCorrectionListerUsecase(providerService, listRecords, zoneCorrectorService, zoneRetrieverService)
|
|
return &Orchestrator{
|
|
RemoteZoneImporter: NewRemoteZoneImporterUsecase(appendDomainLog, providerService, zoneImporter, zoneRetrieverService),
|
|
ZoneCorrectionApplier: NewZoneCorrectionApplierUsecase(appendDomainLog, domainUpdater, zoneCorrectionLister, zoneCreator, zoneGetter, zoneRetrieverService, zoneUpdater),
|
|
ZoneImporter: zoneImporter,
|
|
}
|
|
}
|
|
|
|
// SetSchedulerNotifier sets the optional scheduler notifier on the
|
|
// sub-usecases that create or publish zones.
|
|
func (o *Orchestrator) SetSchedulerNotifier(notifier happydns.SchedulerDomainNotifier) {
|
|
o.RemoteZoneImporter.schedulerNotifier = notifier
|
|
o.ZoneCorrectionApplier.schedulerNotifier = notifier
|
|
}
|