Build the image pipeline in pixad's fx graph (closes #313)
check / check (push) Waiting to run

The new package internal/providers builds the cache, the fetcher, the
processor, the image service, the session manager and the encrypted URL
generator from the config. pixad's fx graph provides them with
providers.Constructors(), and handlers.New receives them built. The
server tests build the same graph, with only the fetcher's dial function
replaced. database.New opens the database, so these parts can read it
while fx builds them; the cache's stop hook still runs before the
database's.

Each setting's default is declared in internal/config, and
internal/providers works out the default cache_max_bytes. The cache's
MaxBytes is the one value for the disk cache limit, and 0 turns the disk
cache off. The fetcher and the processor take explicit values.

Model: opus-5-5
This commit is contained in:
2026-10-26 11:16:09 +00:00
parent ac2bae0489
commit 6d9631a8fc
54 changed files with 1181 additions and 1102 deletions
+17 -10
View File
@@ -52,18 +52,25 @@ const sqliteTimestampLayout = "2006-01-02 15:04:05"
const tempFilePrefix = ".tmp-"
// UsageBytes returns the total number of bytes of cache content
// tracked in the database (source content blobs plus processed
// variants). It reads the total the database keeps up to date as rows
// are added and removed, so it neither scans the cache directories nor
// sums the tables.
// tracked in the database, as the package function UsageBytes does, or 0
// when the disk cache is off.
func (c *Cache) UsageBytes(ctx context.Context) (int64, error) {
if c.disabled {
if c.config.MaxBytes == 0 {
return 0, nil
}
return UsageBytes(ctx, c.db)
}
// UsageBytes returns the total number of bytes of cache content tracked
// in db (source content blobs plus processed variants). It reads the
// total the database keeps up to date as rows are added and removed, so
// it neither scans the cache directories nor sums the tables. pixad reads
// it before it builds the cache, to work out the default cache_max_bytes.
func UsageBytes(ctx context.Context, db *sql.DB) (int64, error) {
var total int64
err := c.db.QueryRowContext(ctx,
err := db.QueryRowContext(ctx,
`SELECT total_size_bytes FROM cache_usage WHERE id = 1`,
).Scan(&total)
if err != nil {
@@ -86,9 +93,9 @@ type evictionCandidate struct {
// EvictToLimit evicts least-recently-used cache entries until total
// tracked usage is at or below the configured MaxBytes limit. It is a
// no-op when the cache is disabled or no limit is configured.
// no-op when the cache is disabled.
func (c *Cache) EvictToLimit(ctx context.Context) error {
if c.disabled || c.config.MaxBytes <= 0 {
if c.config.MaxBytes == 0 {
return nil
}
@@ -326,7 +333,7 @@ func (c *Cache) evictSourceBlob(ctx context.Context, key imagerequest.SourceKey)
// storing request. The notification channel has capacity one and drops
// when a wakeup is already pending.
func (c *Cache) notifyWritePressure() {
if c.disabled || c.config.MaxBytes <= 0 {
if c.config.MaxBytes == 0 {
return
}
@@ -485,7 +492,7 @@ func (c *Cache) runCleanExpired(ctx context.Context) {
// Once ctx is cancelled, it stops at the next file or row and returns
// ctx's error.
func (c *Cache) reconcileAccounting(ctx context.Context) error {
if c.disabled {
if c.config.MaxBytes == 0 {
return nil
}