Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31ed20ec9e | ||
|
|
3daa416f4b | ||
|
|
614bcd9eb6 | ||
|
|
64108c05bb | ||
|
|
ae8b45e93f | ||
|
|
19e018b037 | ||
|
|
ed3f8770e6 |
+6
-2
@@ -68,8 +68,12 @@ RUN apk add --no-cache \
|
|||||||
COPY --from=builder /pixad /usr/local/bin/pixad
|
COPY --from=builder /pixad /usr/local/bin/pixad
|
||||||
COPY deploy/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
COPY deploy/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
# Create non-root user, config directory, and data directory
|
# Create non-root user, config directory, and data directory. pixad
|
||||||
RUN adduser -D -H -s /sbin/nologin pixad && \
|
# gets uid and gid 65532, which host login and system accounts do not
|
||||||
|
# use: a bind-mounted /var/lib/pixa is given to pixad, and on the host
|
||||||
|
# it must not belong to a person's account.
|
||||||
|
RUN addgroup -g 65532 pixad && \
|
||||||
|
adduser -D -H -s /sbin/nologin -u 65532 -G pixad pixad && \
|
||||||
mkdir -p /var/lib/pixa /etc/pixa && \
|
mkdir -p /var/lib/pixa /etc/pixa && \
|
||||||
chown pixad:pixad /var/lib/pixa
|
chown pixad:pixad /var/lib/pixa
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ What the [upaas](https://git.eeqj.de/sneak/upaas) app for pixa needs:
|
|||||||
`healthy`. The probe uses the port from `PORT` (default `8080`), so a
|
`healthy`. The probe uses the port from `PORT` (default `8080`), so a
|
||||||
port changed only in a mounted config file is not seen by it: change
|
port changed only in a mounted config file is not seen by it: change
|
||||||
the port with `PORT`.
|
the port with `PORT`.
|
||||||
- **First run:** create the host directory. It may be owned by root: the
|
- **First run:** create the host directory, owned by root or by uid
|
||||||
container gives it to its `pixad` user when it starts.
|
`65532` and gid `65532`. The server runs as the container's `pixad`
|
||||||
|
user, which has that uid and gid, and the container gives the
|
||||||
|
directory to `pixad` when it starts.
|
||||||
|
|
||||||
## Rationale
|
## Rationale
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ exhaustion
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-09-29 fixed uid and gid for `pixad` (closes #151): the image creates the
|
||||||
|
`pixad` group with gid 65532 and the `pixad` user with uid 65532, instead of
|
||||||
|
the first free uid 1000, so a bind-mounted `/var/lib/pixa` given to `pixad`
|
||||||
|
is not owned on the host by a person's login account; the first-run step of
|
||||||
|
"Running under upaas" in `README.md` names the uid and gid.
|
||||||
- 2026-09-29 `max-age` never outlives an expiring URL (closes #63): both image
|
- 2026-09-29 `max-age` never outlives an expiring URL (closes #63): both image
|
||||||
routes build `Cache-Control` from the request's `Expires`, which an encrypted
|
routes build `Cache-Control` from the request's `Expires`, which an encrypted
|
||||||
URL's expiry now fills too; `max-age` is one year, or the whole seconds left
|
URL's expiry now fills too; `max-age` is one year, or the whole seconds left
|
||||||
@@ -41,12 +46,14 @@ exhaustion
|
|||||||
counts the cached source images and processed variants (`source_content`
|
counts the cached source images and processed variants (`source_content`
|
||||||
plus `variant_content`) and takes their size from `Cache.UsageBytes`,
|
plus `variant_content`) and takes their size from `Cache.UsageBytes`,
|
||||||
instead of reading `request_cache` and `output_content`, which nothing
|
instead of reading `request_cache` and `output_content`, which nothing
|
||||||
writes; those two tables are left in the schema. A miss is counted after
|
writes; those two tables are left in the schema; a disabled disk cache
|
||||||
it is served or fails, even when the request context has ended by then,
|
reports no items and no size. A hit is counted even when the request
|
||||||
with the bytes it read from upstream, so `upstream_fetch_count` and
|
context has ended. A miss is counted after it is served or fails, also
|
||||||
`upstream_fetch_bytes` move, including for an upstream body that fails
|
when the request context has ended by then, with the bytes it read from
|
||||||
partway or a fetched source that then fails the magic byte check;
|
upstream, so `upstream_fetch_count` and `upstream_fetch_bytes` move,
|
||||||
`transform_count` counts each image the image processor transcodes.
|
including for an upstream body that fails partway or a fetched source
|
||||||
|
that then fails the magic byte check; `transform_count` counts each image
|
||||||
|
the image processor transcodes.
|
||||||
- 2026-09-28 strip metadata from processed images (closes #82): every output is
|
- 2026-09-28 strip metadata from processed images (closes #82): every output is
|
||||||
exported with govips' `StripMetadata`, so it carries no EXIF, XMP, IPTC or ICC
|
exported with govips' `StripMetadata`, so it carries no EXIF, XMP, IPTC or ICC
|
||||||
profile; the image is first turned upright with `AutoRotate` (before sizes are
|
profile; the image is first turned upright with `AutoRotate` (before sizes are
|
||||||
|
|||||||
@@ -419,7 +419,9 @@ func (c *Cache) Stats(ctx context.Context) (*CacheStats, error) {
|
|||||||
return nil, fmt.Errorf("failed to get cache stats: %w", err)
|
return nil, fmt.Errorf("failed to get cache stats: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count and size the cached source images and processed variants
|
// Count and size the cached source images and processed variants. A
|
||||||
|
// disabled cache holds none, whatever rows an earlier run left.
|
||||||
|
if !c.disabled {
|
||||||
err = c.db.QueryRowContext(ctx, `
|
err = c.db.QueryRowContext(ctx, `
|
||||||
SELECT (SELECT COUNT(*) FROM source_content)
|
SELECT (SELECT COUNT(*) FROM source_content)
|
||||||
+ (SELECT COUNT(*) FROM variant_content)
|
+ (SELECT COUNT(*) FROM variant_content)
|
||||||
@@ -432,6 +434,7 @@ func (c *Cache) Stats(ctx context.Context) (*CacheStats, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Warn("failed to sum cache size for stats", "error", err)
|
c.log.Warn("failed to sum cache size for stats", "error", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute hit rate as a ratio
|
// Compute hit rate as a ratio
|
||||||
if stats.HitCount+stats.MissCount > 0 {
|
if stats.HitCount+stats.MissCount > 0 {
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ func (s *Service) Get(ctx context.Context, req *ImageRequest) (*ImageResponse, e
|
|||||||
s.log.Error("failed to get cached variant", "key", result.CacheKey, "error", err)
|
s.log.Error("failed to get cached variant", "key", result.CacheKey, "error", err)
|
||||||
// Fall through to re-process
|
// Fall through to re-process
|
||||||
} else {
|
} else {
|
||||||
s.cache.IncrementStats(ctx, true, 0)
|
// Counted also when the request context has ended meanwhile
|
||||||
|
s.cache.IncrementStats(context.WithoutCancel(ctx), true, 0)
|
||||||
|
|
||||||
return &ImageResponse{
|
return &ImageResponse{
|
||||||
Content: reader,
|
Content: reader,
|
||||||
|
|||||||
Reference in New Issue
Block a user