Documentation
¶
Overview ¶
Package cachepreload provides cache preloading when folders are opened.
Index ¶
- Constants
- func MakeInternalRequest(ctx context.Context, cfg InternalRequestConfig, path string) error
- func MakeInternalRequestWithHXTarget(ctx context.Context, cfg InternalRequestConfig, path string, hxTarget string) error
- func PutPreloadTask(task *PreloadTask)
- type DiscardingResponseWriter
- type FolderPreloadTask
- type InternalRequestConfig
- type PreloadConfig
- type PreloadManager
- func (pm *PreloadManager) Configure(cfg PreloadConfig)
- func (pm *PreloadManager) GetMetrics() PreloadMetricsSnapshot
- func (pm *PreloadManager) GetScheduler() *scheduler.Scheduler
- func (pm *PreloadManager) IsEnabled() bool
- func (pm *PreloadManager) ScheduleFolderPreload(ctx context.Context, folderID int64, sessionID string)
- func (pm *PreloadManager) SetEnabled(enabled bool)
- func (pm *PreloadManager) SetOnSetEnabled(fn func(bool))
- func (pm *PreloadManager) Shutdown()
- type PreloadMetrics
- func (m *PreloadMetrics) RecordCancelled()
- func (m *PreloadMetrics) RecordFailure(path string, err error, duration time.Duration)
- func (m *PreloadMetrics) RecordSkipped(reason string)
- func (m *PreloadMetrics) RecordSuccess(path string, duration time.Duration)
- func (m *PreloadMetrics) Summary() string
- type PreloadMetricsSnapshot
- type PreloadService
- type PreloadTask
- type SessionTracker
- type TaskTracker
- func (t *TaskTracker) CancelSessionTasks(sessionID string) []string
- func (t *TaskTracker) IsTaskPending(cacheKey string) bool
- func (t *TaskTracker) RegisterTask(cacheKey, sessionID, taskID string) bool
- func (t *TaskTracker) TryClaimTask(cacheKey string) bool
- func (t *TaskTracker) UnregisterTask(cacheKey string)
Constants ¶
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.
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.
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).