ecc-image-render-service¶
Cloud Run / CQS queue name: ecc-image-render-service
Tech stack: Quarkus (Java), Gradle; Java2D (AWT) for image generation; GCS for LFS writes
ecc-image-render-service is the ECC-side image renderer. It subscribes to ecclink.v1 (and its aliases) as well as storeitemvalues.v1, fetches the referenced ECC model, parameters, and any custom fonts, and produces a rendered PNG for each ESL barcode, writing the output as ecceslimage.v1. It is one of two renderers whose outputs are merged by eslimage-merger; the other is the Studio renderer which produces studioeslimage.v1.
The service package structure reflects the dual heritage of the codebase: rendering logic lives under se.pricer.r3server (ported from Pricer Server), while the DtoFlow integration and CQS subscription management live under se.pricer.platform.
DTO Ownership¶
| DTO | Version | Why |
|---|---|---|
ecceslimage |
v1 | Rendered PNG (stored in LFS) for a specific ESL barcode, keyed t/{tenantId}/s/{storeId}/e/{barcode}/p/{page}/ecceslimage; one record per ESL page; written after each successful render |
CQS Subscriptions¶
| DTO | Version | What the service does on change |
|---|---|---|
ecclink |
v1 | Primary trigger: fetch ECC model + item data, render image, write ecceslimage.v1 |
ecclink |
v1 (alias: by_storeesl) |
Unlink path: if the ecclink for a barcode is gone, delete all ecceslimage children for that ESL |
storeitemvalues |
v1 | Item data changed: look up all ecclink records for that item and re-render |
eccfont |
v1 | Font registry changed: loaded lazily on next render that needs the font (no explicit cache eviction) |
eccmodel |
v1 | Model definition changed: Caffeine cache eviction triggers re-fetch on next render (cache name: ecc-model-cache, max 100 entries) |
eccparameters |
v1 | Store-level ECC parameters changed: Caffeine cache eviction (cache name: ecc-parameters-cache, max 100 entries) |
Processing Logic¶
Events arrive as batched DtoChangeNotification lists from the CQS subscriber. The service groups events by tenant+store before processing.
Per-store batch processing:
-
Parse events: Classify each notification as an
EcclinkV1direct event, aby_storeeslalias event (unlink path), or aStoreItemValuesV1event (item update path). Deduplicate by DTO ID, keeping the event with the latest SLA timestamp. -
Unlink path / cleanup via alias watch (
by_storeeslalias): For each affected barcode alias, attempt to read theecclinkrecord; onNOT_FOUND, issuedeleteChildrenon the store-ESL parent — cascading to allecceslimagepage records for that ESL. Mechanic: this is an instance of the platform-level alias-watch cleanup pattern. -
Resolve Ecclinks:
- Direct
ecclink.v1events: batch-read the Ecclink DTOs. storeitemvalues.v1events: use theby_itemalias index to find all Ecclinks referencing the updated item.-
Deduplicate across both sources.
-
Fetch item values: Collect all item IDs referenced by the resolved Ecclinks (single-item and multi-item variants); batch-read
storeitemvalues.v1. -
Render (sequential per Ecclink to avoid AWT concurrency issues):
- Fetch
eccmodel.v1(Caffeine-cached) for the model ID carried in the Ecclink. - Fetch
eccparameters.v1(Caffeine-cached) for the store. - Map the ESL type ID to
DeviceCapabilities(resolution, color depth, display type). - Determine the IPF (Item Presentation Format) from the item's
presentationproperty (defaults to"NORMAL"). - Select the matching
ESLViewfrom the model's price-view-per-IPF map. - Run
ESLFieldGeneratorto evaluate data bindings, conversions, and rules — producingESLFieldData. - Load any custom fonts referenced by text-box shapes: fetch from
eccfont.v1(via DtoFlow gRPC), read the TTF bytes from LFS, register with AWT'sGraphicsEnvironment. Font registration is cached in aConcurrentHashSetto avoid redundant LFS reads. - Call
EslRenderService.generateImage()— Java2D rendering, returns aBufferedImage. -
Encode to PNG (
ImageIO.write). -
Write to LFS and DtoFlow (parallel):
- Each rendered PNG is written to GCS asynchronously (virtual threads).
- Once all LFS writes succeed, a single
putManycall commits allecceslimage.v1records to DtoFlow in one batch.
Rotation: The eccmodel.v1 record carries a rotation field (CW_90 or NONE). This is embedded in the ecceslimage.rotation field so that the downstream eslimage-merger and pricer-server know how to orient the image before sending it to hardware.
Error handling: If any single LFS write or render fails in a batch, the entire batch throws to allow CQS retry. Partial success is not committed.
Related services¶
- ecclink-projector — upstream; produces
ecclink.v1fromlink.v2 - item-registry — upstream; produces
storeitemvalues.v1from ERP/PIM data - eslimage-merger — downstream; merges
ecceslimage.v1withstudioeslimage.v1→eslimage.v1 - dtoflow-lfs — LFS layer; GCS bucket
dtoflow-lfs-eu-n1-{env}used for storing rendered PNGs