Files
member-console/internal/workflows/fedwiki/schedule.go

197 lines
6.1 KiB
Go

package fedwiki
import (
"context"
"fmt"
"log/slog"
"time"
"git.coopcloud.tech/wiki-cafe/member-console/internal/workflows/queues"
"go.temporal.io/sdk/client"
)
const (
// SyncScheduleID is the unique identifier for the FedWiki site sync schedule.
SyncScheduleID = "fedwiki-site-sync"
// SyncWorkflowID is the workflow ID used for sync workflow executions.
SyncWorkflowID = "fedwiki-site-sync-workflow"
// DefaultSyncInterval is the default interval between site syncs.
DefaultSyncInterval = 1 * time.Hour
)
// ScheduleConfig holds configuration for the FedWiki sync schedule.
type ScheduleConfig struct {
// Interval is how often to run the sync workflow.
Interval time.Duration
// DefaultUserID is the user ID to assign to orphaned sites.
DefaultUserID int64
// TriggerImmediately runs the sync immediately when creating the schedule.
TriggerImmediately bool
}
// DefaultScheduleConfig returns a default schedule configuration.
func DefaultScheduleConfig() ScheduleConfig {
return ScheduleConfig{
Interval: DefaultSyncInterval,
DefaultUserID: 1, // Typically the admin/system user
TriggerImmediately: true,
}
}
// ScheduleManager manages Temporal schedules for FedWiki operations.
type ScheduleManager struct {
client client.Client
logger *slog.Logger
}
// NewScheduleManager creates a new ScheduleManager.
func NewScheduleManager(c client.Client, logger *slog.Logger) *ScheduleManager {
return &ScheduleManager{
client: c,
logger: logger,
}
}
// EnsureSyncSchedule creates or updates the FedWiki site sync schedule.
// If the schedule already exists, it updates the schedule's spec.
// If it doesn't exist, it creates a new schedule.
func (m *ScheduleManager) EnsureSyncSchedule(ctx context.Context, cfg ScheduleConfig) error {
if cfg.Interval == 0 {
cfg.Interval = DefaultSyncInterval
}
scheduleClient := m.client.ScheduleClient()
// Try to get the existing schedule
handle := scheduleClient.GetHandle(ctx, SyncScheduleID)
_, err := handle.Describe(ctx)
if err == nil {
// Schedule exists, update it
m.logger.Info("updating existing FedWiki sync schedule",
slog.Duration("interval", cfg.Interval))
err = handle.Update(ctx, client.ScheduleUpdateOptions{
DoUpdate: func(schedule client.ScheduleUpdateInput) (*client.ScheduleUpdate, error) {
schedule.Description.Schedule.Spec = &client.ScheduleSpec{
Intervals: []client.ScheduleIntervalSpec{
{Every: cfg.Interval},
},
}
schedule.Description.Schedule.Action = &client.ScheduleWorkflowAction{
ID: SyncWorkflowID,
Workflow: SyncFedWikiSitesWorkflow,
TaskQueue: queues.Main,
Args: []interface{}{
SyncFedWikiSitesWorkflowInput{
DefaultUserID: cfg.DefaultUserID,
},
},
}
return &client.ScheduleUpdate{
Schedule: &schedule.Description.Schedule,
}, nil
},
})
if err != nil {
return fmt.Errorf("failed to update sync schedule: %w", err)
}
m.logger.Info("FedWiki sync schedule updated successfully")
return nil
}
// Schedule doesn't exist, create it
m.logger.Info("creating FedWiki sync schedule",
slog.Duration("interval", cfg.Interval),
slog.Bool("triggerImmediately", cfg.TriggerImmediately))
_, err = scheduleClient.Create(ctx, client.ScheduleOptions{
ID: SyncScheduleID,
Spec: client.ScheduleSpec{
Intervals: []client.ScheduleIntervalSpec{
{Every: cfg.Interval},
},
},
Action: &client.ScheduleWorkflowAction{
ID: SyncWorkflowID,
Workflow: SyncFedWikiSitesWorkflow,
TaskQueue: queues.Main,
Args: []interface{}{
SyncFedWikiSitesWorkflowInput{
DefaultUserID: cfg.DefaultUserID,
},
},
},
TriggerImmediately: cfg.TriggerImmediately,
})
if err != nil {
return fmt.Errorf("failed to create sync schedule: %w", err)
}
m.logger.Info("FedWiki sync schedule created successfully",
slog.String("scheduleID", SyncScheduleID))
return nil
}
// DeleteSyncSchedule deletes the FedWiki site sync schedule.
func (m *ScheduleManager) DeleteSyncSchedule(ctx context.Context) error {
handle := m.client.ScheduleClient().GetHandle(ctx, SyncScheduleID)
err := handle.Delete(ctx)
if err != nil {
return fmt.Errorf("failed to delete sync schedule: %w", err)
}
m.logger.Info("FedWiki sync schedule deleted", slog.String("scheduleID", SyncScheduleID))
return nil
}
// PauseSyncSchedule pauses the FedWiki site sync schedule.
func (m *ScheduleManager) PauseSyncSchedule(ctx context.Context, note string) error {
handle := m.client.ScheduleClient().GetHandle(ctx, SyncScheduleID)
err := handle.Pause(ctx, client.SchedulePauseOptions{
Note: note,
})
if err != nil {
return fmt.Errorf("failed to pause sync schedule: %w", err)
}
m.logger.Info("FedWiki sync schedule paused",
slog.String("scheduleID", SyncScheduleID),
slog.String("note", note))
return nil
}
// UnpauseSyncSchedule unpauses (resumes) the FedWiki site sync schedule.
func (m *ScheduleManager) UnpauseSyncSchedule(ctx context.Context, note string) error {
handle := m.client.ScheduleClient().GetHandle(ctx, SyncScheduleID)
err := handle.Unpause(ctx, client.ScheduleUnpauseOptions{
Note: note,
})
if err != nil {
return fmt.Errorf("failed to unpause sync schedule: %w", err)
}
m.logger.Info("FedWiki sync schedule unpaused",
slog.String("scheduleID", SyncScheduleID),
slog.String("note", note))
return nil
}
// TriggerSyncNow triggers an immediate execution of the sync workflow.
func (m *ScheduleManager) TriggerSyncNow(ctx context.Context) error {
handle := m.client.ScheduleClient().GetHandle(ctx, SyncScheduleID)
err := handle.Trigger(ctx, client.ScheduleTriggerOptions{})
if err != nil {
return fmt.Errorf("failed to trigger sync schedule: %w", err)
}
m.logger.Info("FedWiki sync triggered", slog.String("scheduleID", SyncScheduleID))
return nil
}
// GetSyncScheduleInfo returns information about the sync schedule.
func (m *ScheduleManager) GetSyncScheduleInfo(ctx context.Context) (*client.ScheduleDescription, error) {
handle := m.client.ScheduleClient().GetHandle(ctx, SyncScheduleID)
desc, err := handle.Describe(ctx)
if err != nil {
return nil, fmt.Errorf("failed to describe sync schedule: %w", err)
}
return desc, nil
}