cachepreload

package
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package cachepreload provides cache preloading when folders are opened.

Index

Constants

View Source
const InternalPreloadHeader = "X-SFPG-Internal-Preload"

InternalPreloadHeader is set on internal preload requests so handlers can skip scheduling another preload (avoiding cascading preloads).

Variables

This section is empty.

Functions

func MakeInternalRequest

func MakeInternalRequest(ctx context.Context, cfg InternalRequestConfig, path string) error

MakeInternalRequest makes an internal HTTP request to warm the cache. The request goes through the full middleware chain to ensure proper cache entries.

IMPORTANT: Does NOT set HX-Request header - this ensures full-page cache entries are created (partials have Cache-Control: no-store and won't be cached).

func MakeInternalRequestWithHXTarget added in v0.10.0

func MakeInternalRequestWithHXTarget(ctx context.Context, cfg InternalRequestConfig, path string, hxTarget string) error

MakeInternalRequestWithHXTarget makes an internal HTTP request with HTMX variant headers so the stored cache key matches real browser HTMX requests. When hxTarget is non-empty, sets HX-Request: true and HX-Target: hxTarget; when empty, does not set HX headers (full-page style).

func PutPreloadTask

func PutPreloadTask(task *PreloadTask)

PutPreloadTask returns a PreloadTask to the pool.

Types

type DiscardingResponseWriter added in v0.3.0

type DiscardingResponseWriter struct {
	// contains filtered or unexported fields
}

DiscardingResponseWriter is a ResponseWriter that discards the body immediately to avoid buffering large responses during cache warming.

func (*DiscardingResponseWriter) Header added in v0.3.0

func (w *DiscardingResponseWriter) Header() http.Header

Header returns the response headers map.

func (*DiscardingResponseWriter) StatusCode added in v0.3.0

func (w *DiscardingResponseWriter) StatusCode() int

StatusCode returns the recorded HTTP status code.

func (*DiscardingResponseWriter) Write added in v0.3.0

func (w *DiscardingResponseWriter) Write(b []byte) (int, error)

Write discards the response body and reports the input length.

func (*DiscardingResponseWriter) WriteHeader added in v0.3.0

func (w *DiscardingResponseWriter) WriteHeader(code int)

WriteHeader records the HTTP status code without writing to a client.

type FolderPreloadTask

type FolderPreloadTask struct {
	FolderID        int64                     // folder to preload (direct children only)
	SessionID       string                    // for task cancellation when user navigates away
	ETagVersion     string                    // cache-busting query (e.g. "v=20260201-01")
	CacheableRoutes []string                  // route prefixes that are cacheable (e.g. "/gallery/", "/info/")
	DBRoPool        *dbconnpool.DbSQLConnPool // read-only pool for GetPreloadRoutesByFolderID
	TaskTracker     *TaskTracker              // deduplication; TryClaimTask before scheduling
	Scheduler       *scheduler.Scheduler      // schedules per-path PreloadTask
	RequestConfig   InternalRequestConfig     // handler and ETag version for internal requests
	Metrics         *PreloadMetrics           // optional; records skipped/scheduled
	GetQueries      func(*dbconnpool.CpConn) interfaces.HandlerQueries
}

FolderPreloadTask checks a folder's contents and schedules individual preload tasks. It respects CacheableRoutes and uses TaskTracker for deduplication.

func (*FolderPreloadTask) Run

func (t *FolderPreloadTask) Run(ctx context.Context) error

Run implements scheduler.Task. Uses GetPreloadRoutesByFolderID as the source of truth (direct children only).

type InternalRequestConfig

type InternalRequestConfig struct {
	// Handler is the HTTP handler wrapped with full middleware chain
	// (cache middleware, etc.)
	Handler http.Handler

	// ETagVersion for cache key query string
	ETagVersion string
}

InternalRequestConfig holds dependencies for making internal HTTP requests.

type PreloadConfig

type PreloadConfig struct {
	TaskTracker    *TaskTracker
	SessionTracker *SessionTracker
	DBRoPool       *dbconnpool.DbSQLConnPool
	GetQueries     func(*dbconnpool.CpConn) interfaces.HandlerQueries
	GetHandler     func() http.Handler // Lazy: full middleware chain
	GetETagVersion func() string
	Metrics        *PreloadMetrics
}

PreloadConfig holds dependencies for ScheduleFolderPreload.

type PreloadManager

type PreloadManager struct {
	// contains filtered or unexported fields
}

PreloadManager manages the cache preload scheduler lifecycle with dynamic enable/disable support. It implements PreloadService and can replace the scheduler instance when toggling.

func NewPreloadManager

func NewPreloadManager(cacheableRoutes []string, initialEnabled bool) *PreloadManager

NewPreloadManager creates a new PreloadManager with the given cacheable routes. If initialEnabled is true, the scheduler is started immediately.

func (*PreloadManager) Configure

func (pm *PreloadManager) Configure(cfg PreloadConfig)

Configure sets dependencies for ScheduleFolderPreload. Call after creation.

func (*PreloadManager) GetMetrics

func (pm *PreloadManager) GetMetrics() PreloadMetricsSnapshot

GetMetrics returns the current preload metrics snapshot.

func (*PreloadManager) GetScheduler

func (pm *PreloadManager) GetScheduler() *scheduler.Scheduler

GetScheduler returns the current scheduler for testing. Returns nil if disabled.

func (*PreloadManager) IsEnabled

func (pm *PreloadManager) IsEnabled() bool

IsEnabled returns whether cache preloading is currently enabled.

func (*PreloadManager) ScheduleFolderPreload

func (pm *PreloadManager) ScheduleFolderPreload(ctx context.Context, folderID int64, sessionID string)

ScheduleFolderPreload schedules background cache preload for a folder. sessionID is used for task cancellation when user navigates away. Non-blocking.

func (*PreloadManager) SetEnabled

func (pm *PreloadManager) SetEnabled(enabled bool)

SetEnabled dynamically enables or disables cache preloading. When disabled, all pending tasks are cancelled.

func (*PreloadManager) SetOnSetEnabled

func (pm *PreloadManager) SetOnSetEnabled(fn func(bool))

SetOnSetEnabled sets an optional callback invoked when SetEnabled is called (for tests).

func (*PreloadManager) Shutdown

func (pm *PreloadManager) Shutdown()

Shutdown gracefully shuts down the PreloadManager, stopping the scheduler if running. Call this during application shutdown.

type PreloadMetrics

type PreloadMetrics struct {
	TasksScheduled atomic.Int64
	TasksCompleted atomic.Int64
	TasksFailed    atomic.Int64
	TasksCancelled atomic.Int64
	TasksSkipped   atomic.Int64 // Due to deduplication or existing cache
	TotalDuration  atomic.Int64 // Nanoseconds
}

PreloadMetrics collects observability data for cache preloading operations.

func (*PreloadMetrics) RecordCancelled

func (m *PreloadMetrics) RecordCancelled()

RecordCancelled records a cancelled task.

func (*PreloadMetrics) RecordFailure

func (m *PreloadMetrics) RecordFailure(path string, err error, duration time.Duration)

RecordFailure records a failed preload.

func (*PreloadMetrics) RecordSkipped

func (m *PreloadMetrics) RecordSkipped(reason string)

RecordSkipped records a skipped task (deduplicated or cached).

func (*PreloadMetrics) RecordSuccess

func (m *PreloadMetrics) RecordSuccess(path string, duration time.Duration)

RecordSuccess records a successful preload.

func (*PreloadMetrics) Summary

func (m *PreloadMetrics) Summary() string

Summary returns a string summary for logging.

type PreloadMetricsSnapshot

type PreloadMetricsSnapshot struct {
	TasksScheduled int64         `json:"tasks_scheduled"`
	TasksCompleted int64         `json:"tasks_completed"`
	TasksFailed    int64         `json:"tasks_failed"`
	TasksCancelled int64         `json:"tasks_cancelled"`
	TasksSkipped   int64         `json:"tasks_skipped"`
	TotalDuration  time.Duration `json:"total_duration"`
}

PreloadMetricsSnapshot holds a snapshot of preload metrics.

type PreloadService

type PreloadService interface {
	// ScheduleFolderPreload schedules background cache preload for a folder.
	// sessionID is used for task cancellation when user navigates away.
	// Non-blocking (fire-and-forget).
	ScheduleFolderPreload(ctx context.Context, folderID int64, sessionID string)

	// SetEnabled dynamically enables or disables cache preloading.
	// When disabled, all pending tasks are cancelled.
	SetEnabled(enabled bool)

	// IsEnabled returns whether cache preloading is currently enabled.
	IsEnabled() bool
}

PreloadService defines the interface for cache preloading operations. Handlers receive this interface via dependency injection (Option B pattern).

type PreloadTask

type PreloadTask struct {
	CacheKey      string
	Path          string
	HXTarget      string // optional; when set, request uses HX-Request/HX-Target
	TaskTracker   *TaskTracker
	RequestConfig InternalRequestConfig
	Metrics       *PreloadMetrics
}

PreloadTask makes an internal HTTP request to warm the cache for a single endpoint. When HXTarget is non-empty, the request uses HTMX variant headers so the stored cache entry matches real browser requests (e.g. info box, lightbox).

func GetPreloadTask

func GetPreloadTask() *PreloadTask

GetPreloadTask retrieves a PreloadTask from the pool.

func (*PreloadTask) Run

func (t *PreloadTask) Run(ctx context.Context) error

Run implements scheduler.Task.

type SessionTracker

type SessionTracker struct {
	// contains filtered or unexported fields
}

SessionTracker manages per-session preload state for folder navigation cancellation. When a user navigates to a new folder, outstanding tasks for the previous folder are cancelled to avoid wasting resources.

func (*SessionTracker) Cleanup

func (s *SessionTracker) Cleanup(maxAge time.Duration)

Cleanup removes stale session entries (call periodically or on session end).

func (*SessionTracker) OnFolderOpen

func (s *SessionTracker) OnFolderOpen(sessionID string, folderID int64) (previousFolderID int64)

OnFolderOpen is called when a user opens a folder. Returns the previous folderID (0 if none) for task cancellation.

type TaskTracker

type TaskTracker struct {
	// contains filtered or unexported fields
}

TaskTracker provides deduplication for preload tasks using full cache keys. It prevents scheduling duplicate tasks for the same cache entry.

func (*TaskTracker) CancelSessionTasks

func (t *TaskTracker) CancelSessionTasks(sessionID string) []string

CancelSessionTasks marks all tasks for a session as cancelled. Returns list of taskIDs to cancel via scheduler.RemoveTask().

func (*TaskTracker) IsTaskPending

func (t *TaskTracker) IsTaskPending(cacheKey string) bool

IsTaskPending returns true if a task for this cache key is already scheduled/running.

func (*TaskTracker) RegisterTask

func (t *TaskTracker) RegisterTask(cacheKey, sessionID, taskID string) bool

RegisterTask marks a cache key as having a pending task. Returns false if task already pending (caller should skip).

func (*TaskTracker) TryClaimTask added in v0.3.0

func (t *TaskTracker) TryClaimTask(cacheKey string) bool

TryClaimTask attempts to claim a cache key for processing. Returns true if the key was successfully claimed, false if it's already claimed. This method is thread-safe and ensures only one goroutine processes a given cache key.

func (*TaskTracker) UnregisterTask

func (t *TaskTracker) UnregisterTask(cacheKey string)

UnregisterTask removes a cache key from pending (called when task completes).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL