You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
image_pipe_url
Removed
Breaking:ImagePipe.Plan.Source.Path, ImagePipe.Plan.Source.URL, and ImagePipe.Plan.Source.Object. They are now ImagePipe.Source.Path, ImagePipe.Source.URL, and ImagePipe.Source.Object in image_pipe, whose
custom source adapters receive them.
The dependency on mime. The package depends only on nimble_options and color at runtime.
image_pipe
Added
SVG sources, when the optional image_pipe_svg package is installed.
An SVG renders straight at the size the request needs, so it stays sharp
at any size, and a resize can make it larger than its own width and height without enlarge, up to the input pixel limit, past which the
rendered image is enlarged. Regions and crops in pixels measure the SVG at
its own size. With no format and no negotiated format, the result is a
PNG. Watermark images can be SVGs too, and render at the size they're
drawn. Without image_pipe_svg, SVG sources still fail with 415.
The :svg option configures SVG sources: :font_dirs and :fallback_family for the fonts SVG text renders in (no system fonts are
used), and :max_bytes, :max_render_work, and :max_render_pixels to
limit the work an SVG can cause.
A [:source, :svg_render] span wraps rendering an SVG original or
watermark, with its intrinsic and rendered sizes and the estimated work,
and names the limit that rejected an SVG. The default Logger logs it.
cache and input_cache delete metadata files they can't read, such as
ones another ImagePipe version wrote, and their bodies, once the files are
more than an hour old. The [:cache, :sweep] event reports them as :unreadable.
[:cache, :stage] reports writes the cache drops to keep up with its
storage as :stage_dropped, for processed images and originals, and
carries :pool. The default Logger logs dropped writes at :warning.
[:cache, :coordination] carries reason: :deadline when a request stops
waiting for another request's image because it wasn't stored in time.
The image_pipe.request span carries a request_id attribute when Logger
metadata has a :request_id, such as the one Plug.RequestId sets.
The [:cache, :lookup], [:cache, :write], and [:cache, :stage]
telemetry events carry :cache_key, the hash of the entry's cache key, and [:cache, :lookup] carries :entry, which says whether it read a processed
response or a source record. The tracer adds them to their spans and span
events.
The [:cache, :write] stop event carries :estimated_cost_us, the work
the cache estimates it took to make a processed image. The tracer adds it
to the span.
The [:cache, :write] stop event carries :bytes, the size of the stored
body, so dividing it by the span's duration gives a rough write speed for the
cache storage. [:cache, :lookup] carries :bytes on a hit for a processed
response. The tracer adds :bytes to both spans, and the default Logger
logs it.
A [:source, :decode_open] span wraps each time libvips opens the original,
so a trace shows how often a request opens it. The default Logger doesn't log
it.
Changed
With image_pipe_svg installed, cache keys and ETags include the resvg
version, the fonts, and the fallback family, so every cached image misses
once after installing it, and again after changing the fonts or fallback
family, or upgrading image_pipe_svg to a version that renders SVGs
differently.
Breaking: An HTTP source's allowed_hosts entry without a port allows
only the scheme's default port, 80 or 443, including for redirect targets.
Before, any port on a listed host was reachable. Add an entry with the port,
such as "assets.example.com:8443", for an origin on another port. A base_url with a non-default port needs that port in allowed_hosts when you
set the list. A malformed entry, such as "assets.example.com:https", now
fails at startup.
A response to a URL with expires drops stale-while-revalidate and stale-if-error, including ones the host sets, because caches can't use them
alongside its must-revalidate.
Processed images and originals cached by an earlier version are not
reused, because the cache key changed and entry files are named
differently. The cache refills as requests come in, and deletes the old
files as leftover files.
Requests for PNG and other sources that need no shrink-on-load open the
source once instead of twice, which saves about 0.3 ms per request.
A custom detector's identity/1, available?/1, and ready?/1 receive only :classes, as detect/2 already did. They no longer see the mount's other
configuration.
Breaking: The source identifiers a custom source adapter receives are ImagePipe.Source.Path, ImagePipe.Source.URL, and ImagePipe.Source.Object.
Replace ImagePipe.Plan.Source.Path, .URL, and .Object in your adapter.
Breaking: A source's internal_cache takes :enabled or :disabled,
and defaults to :enabled. Replace internal_cache: :auto, which meant the
same as :enabled.
Breaking:c:ImagePipe.Source.S3.CredentialProvider.fetch_credentials/2
takes the bucket and the provider's options. Change your provider's fetch_credentials/3 to fetch_credentials/2 by dropping the third
argument, which was always [].
Breaking:cache and input_cache take the file system cache's options
directly. Replace cache: {ImagePipe.Cache.FileSystem, root: "..."} with cache: [root: "..."], and the same for input_cache. The server's [cache] configuration is unchanged.
Breaking: The tracer now creates OpenTelemetry spans as they happen, and
needs the OpenTelemetry SDK in your application. Remove the exporter:
option from ImagePipe.Telemetry.attach_tracer/1 and the ImagePipe.Telemetry.Trace.OtelIdGeneratorid_generator setting from your :opentelemetry configuration. To print spans without a backend, use the
SDK's stdout exporter. Span and trace IDs now come from the SDK, and each
span reaches the SDK when it ends, not when the request finishes.
A request's spans join the trace of the span that is current when the
request starts, such as one from your Phoenix or Bandit instrumentation.
This includes ImagePipe.run/4 in an instrumented job. With extract_inbound: true, the inbound traceparent applies only when no span
is current.
Spans your own code opens inside ImagePipe's processes, such as in a custom
source or detector, nest under the request's spans, with or without the
tracer attached.
A request that continues an inbound trace follows the caller's sampled
flag under the SDK's default parent-based sampler. It was always recorded
before.
Breaking:[:cache, :eviction, :stop] reports the entries a write
evicts, with trigger: :admission, and the startup scan's batches with trigger: :startup. Update handlers that match trigger: :reconcile.
Responses no longer wait for the cache's disk. A processed image is stored
in the background after it's sent, and a downloaded original while the
request processes it. The [:cache, :write] span can end after the
request.
A request waiting for another request's image or original stops waiting
when the image or original isn't stored 2 seconds after it was sent or
downloaded.
When the disk can't keep up, writes are dropped, and unfinished writes
count against max_size_bytes. An entry larger than a twentieth of max_size_bytes, or 256 MiB, is never stored (see writing entries).
trim is faster on images under a megapixel: 2 ms instead of 6.5 ms on a
256×256 image.
Breaking:cache and input_cache need max_size_bytes, and an
ImagePipe instance (see ImagePipe.child_spec/1). Add max_size_bytes to
each cache, and to the options of ImagePipe.Cache.FileSystem.get/2, and
move a configuration with a cache from ImagePipe.Plug options or an ImagePipe.run/4 call into an instance. run/4 with an instance name
can't set cache or input_cache per call.
Breaking: Each root of cache and input_cache serves one node. An
instance writes a .image-pipe-owner file into each cache's root.
While another node keeps that file updated, the instance logs an error and
runs without that cache, and it takes the root over once the other node
stops. Give each replica its own cache directories, such as its own volume.
When a node is killed, a node on another host that starts after the kill
takes over its root about 30 seconds after starting.
cache and input_cache keep the entries that are requested often and
took the most work to make for their size. For a processed image, that work
is estimated from the request instead of timed (see work to make an entry).
On startup a cache reads only file names, so a large cache is ready sooner.
Removed
Breaking:ImagePipe.Transform.Detector.Composite.new/1 and default/0. A detector is configured as a module, so a composite struct
could not be configured. Configure ImagePipe.Transform.Detector.Composite
itself to get the default face and object detectors.
Breaking: Bounded caches keep request counts in memory only. Remove node_id, state_dir, flush_interval, cleanup_interval, and state_ttl from cache and input_cache. After a restart, a bounded
cache keeps its entries and learns again which are requested most. You can
delete the .cache_state directory under each bounded cache's root.
The [:cache, :warm_start], [:cache, :flush, :stop], and [:cache, :cleanup, :stop] telemetry events.
Breaking: The eviction_victim_limit and reconcile_interval options
of cache and input_cache. Remove them from your configuration. A write
now evicts every entry it needs before it's stored, so the stored bodies
stay under max_size_bytes once the startup scan has run, and the cache no
longer runs a background eviction pass every minute.
Breaking: The window_ratio, sketch_depth, sketch_width, aging_sample_size, doorkeeper_cardinality, doorkeeper_fpr, and path_prefix options of cache and input_cache. Remove them from your
configuration. The cache no longer reads or cleans up the old entries under
a path_prefix directory, so delete that directory.
Breaking: The rescan_interval option of cache and input_cache, and
the [:cache, :rescan] telemetry event. Remove rescan_interval from your
configuration. A cache deletes leftover files after its startup scan
and then every 24 hours.
[:cache, :stage] no longer reports cache: :stage_cleanup_error.
Discarding a staged entry doesn't fail.
Breaking:ImagePipe.Telemetry.Trace.LogExporter, ImagePipe.Telemetry.Trace.OpenTelemetryExporter, ImagePipe.Telemetry.Trace.OtelIdGenerator, ImagePipe.Telemetry.Trace.Span, ImagePipe.Telemetry.Trace.Context, and
the ImagePipe.Telemetry.Trace.Exporter behaviour.
Fixed
[:cache, :write] reports a write error instead of cache: :write when
the cache's process isn't running, since nothing was stored.
A crop placed with focus on an image with an EXIF orientation other than
1 or 5 could land one pixel off from the same crop on an untagged image,
when the crop's position fell on a half pixel.
With max-bytes, a quality search that ran out of encode attempts
shipped the lowest quality, even when it had already encoded a higher one
that fit the budget. It now ships the highest encoded quality that fits. When
only the lowest quality fits, the X-ImagePipe-AQ-Outcome debug header and
the [:encode, :search] telemetry event report hit instead of best_effort.
With allow_origin set, cross-origin scripts can send conditional
requests such as If-None-Match, and can read response headers such as ETag and Content-Disposition. Preflight requests now get Access-Control-Allow-Headers: *, and responses get Access-Control-Expose-Headers: *.
A comma inside a quoted Accept parameter, as in image/webp;x="a,b";q=0, no longer splits the entry. The split dropped the q=0, so ImagePipe could choose a format the client had excluded.
input_cache rejects max_body_bytes instead of ignoring it, and
configuration fails with an unknown-option error. Remove the option from input_cache.
Concurrent fetches from an HTTP source (ImagePipe.Source.HTTP) just after
startup could exit with :noproc. They now wait for the connection pool to
start.
A CMYK or other non-RGB source with an embedded color profile and more
pixels than max_intermediate_pixels fails with 422, like other oversized
images, instead of 415.
The source cache stores and reuses originals whose Cache-Control has a
qualified private="..." or no-cache="..." naming only headers ImagePipe
doesn't keep, such as private="Set-Cookie". They were treated as
unqualified private (never stored) or no-cache (revalidated on every
request).