eslimage-merger¶
Cloud Run / CQS queue name: eslimage-merger
Tech stack: Quarkus (Java), Gradle
eslimage-merger solves a structural problem: the Pricer platform has two independent renderers — ecc-image-render-service (produces ecceslimage.v1) and the Studio renderer (produces studioeslimage.v1) — and the downstream consumer (pricer-server, which transmits to hardware) needs a single unified image record. eslimage-merger subscribes to both renderer outputs and merges them into one eslimage.v1 record per ESL per page.
The core challenge is a race condition: the two renderers work independently and will generally complete at different times for the same ESL. eslimage-merger must not produce a merged record from only one renderer's output when the other is still pending. It waits until both renderers have written output for the same (tenant, store, barcode, page) tuple before writing the merged result.
DTO Ownership¶
| DTO | Version | Why |
|---|---|---|
eslimage |
v1 | Unified per-ESL per-page image record; keyed t/{tenantId}/s/{storeId}/e/{barcode}/p/{page}/eslimage; contains the LFS file path, rotation hint, and metadata derived from the two renderer outputs; written once both ecceslimage.v1 and studioeslimage.v1 are present |
CQS Subscriptions¶
| DTO | Version | What the service does on change |
|---|---|---|
studioeslimage |
v1 | Studio renderer produced a new image: read the paired ecceslimage.v1; if present, write merged eslimage.v1; if absent, store and wait |
ecceslimage |
v1 | ECC renderer produced a new image: read the paired studioeslimage.v1; if present, write merged eslimage.v1; if absent, store and wait |
The race condition problem¶
Without eslimage-merger, any downstream subscriber to eslimage.v1 would need to be aware of both renderer types, implement its own wait logic, and handle partial state. That creates coupling and duplication.
eslimage-merger centralises the rendezvous. When a studioeslimage.v1 change arrives:
- Compute the matching
ecceslimage.v1ID from the same(tenant, store, barcode, page)coordinates. - Attempt to read
ecceslimage.v1from DtoFlow. - If found: both renderer outputs are available. Merge and write
eslimage.v1. - If not found: the ECC renderer hasn't finished yet (or the ESL is not an ECC type). Do not write. The merge will happen when the
ecceslimage.v1event arrives and re-checksstudioeslimage.v1.
The same logic runs symmetrically when an ecceslimage.v1 event arrives first.
Non-ECC ESLs: Some ESLs are rendered only by Studio (they have no ECC model). For these, ecceslimage.v1 will never be written. eslimage-merger therefore applies a configurable fallback: if one renderer's output is absent after a timeout or per a store/tenant configuration flag, the merge can proceed with only the available side. This ensures non-ECC ESLs are not blocked waiting for an ECC image that will never arrive.
Deletion propagation: If either renderer deletes its output (e.g., because the link was removed), eslimage-merger deletes the corresponding eslimage.v1 record, which in turn triggers pricer-server to unregister or update the ESL.
Processing Logic¶
For each incoming event (either studioeslimage.v1 or ecceslimage.v1):
- Parse the DTO ID to extract
tenantId,storeId,barcode,page. - Determine if the event is a write or a delete.
- For a write event:
- Read the counterpart DTO from DtoFlow.
- If counterpart is absent, return — nothing to merge yet.
- Select the primary image source (typically
studioeslimageis preferred for thefilePath;ecceslimagesupplies therotationhint if non-zero). - Construct the merged
eslimage.v1with the resolvedfilePath,rotation, and both source references. - Write
eslimage.v1to DtoFlow. - For a delete event:
- Delete
eslimage.v1for the same coordinates.
Related services¶
- ecc-image-render-service — upstream; produces
ecceslimage.v1 - Studio renderer — upstream; produces
studioeslimage.v1 - pricer-server — downstream consumer of
eslimage.v1; transmits to physical ESL hardware - dtoflow-migration-helper — during PLT-2484 migration, maps
renderedimage.v1↔studioeslimage.v1