happyDomain/internal/usecase/orchestrator/factory.go
Pierre-Olivier Mercier ac50d02819 checkers: add incremental scheduler updates on domain/zone changes
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.
2026-04-15 19:30:14 +07:00

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
}