Skip to content

fix(pricing): bundle snapshot resources into native image#836

Open
ShubhamDX wants to merge 2 commits into
floci-io:mainfrom
ShubhamDX:fix/pricing-native-resources
Open

fix(pricing): bundle snapshot resources into native image#836
ShubhamDX wants to merge 2 commits into
floci-io:mainfrom
ShubhamDX:fix/pricing-native-resources

Conversation

@ShubhamDX
Copy link
Copy Markdown
Contributor

Summary

Reported by @cfranzen on #821: when running Floci as a container, the Pricing service returns no service codes and PricingService.load() produces no log output at all — symptoms that point to the bundled snapshot files being absent rather than malformed.

Root cause: the standard Floci container ships the GraalVM native binary, and pricing-snapshots/** was never registered as a runtime resource in the native-image config, so GraalVM stripped every JSON file from the image. The classpath read in SnapshotLoader.readJson returned null for the services.json lookup, which short-circuits load() before it logs anything.

Fix

Two small changes:

  1. Register the snapshot tree under quarkus.native.resources.includes. Quarkus's static resource analysis can't detect paths assembled at call time ("pricing-snapshots/" + relativePath), so an explicit include is needed.
  2. Switch to PricingService.class.getClassLoader() for the snapshot read. In a GraalVM native image the thread context classloader can be the bootstrap loader, which sees no application resources, while the class's own loader always sees what's bundled into the image.

Test plan

  • ./mvnw test -Dtest=PricingIntegrationTest — 26/26 green locally on JVM (Java 25)
  • CI to run the native-image build + compatibility suite, which is what the original symptom required

I don't have a local GraalVM toolchain set up to validate the native build directly; CI will exercise the published image path that triggered the report.

Refs: #821 (comment)

The bundled pricing-snapshots tree was missing from the GraalVM
native-image build, so the standard Floci container (which ships
the native binary) had no service codes available — the Pricing
snapshot loader silently returned null because the JSON files
weren't present at runtime.

Two changes:

1. Register `pricing-snapshots/**` under
   `quarkus.native.resources.includes` so GraalVM bundles every
   snapshot file into the image. Quarkus's static analysis cannot
   detect resource paths constructed dynamically (the loader joins
   `pricing-snapshots/` with a per-call relative path), so an
   explicit include is required.

2. Read snapshot resources via the class's own `ClassLoader` rather
   than the thread context loader. In a native image the thread
   context loader can be the bootstrap loader, which sees no
   application resources, while the class's loader sees everything
   bundled into the image.

Reported by @cfranzen against floci-io#821 — Pricing service returned no
service codes when called via Testcontainers and `load()` produced
no log output, indicating the snapshot files were absent rather
than malformed.

Refs: floci-io#821 (comment)
@ShubhamDX
Copy link
Copy Markdown
Contributor Author

Verified locally against the native build:

$ docker build -f docker/Dockerfile.native -t floci-pricing-fix:test .
$ docker run -d --name floci -p 14566:4566 floci-pricing-fix:test

$ curl -s -X POST http://localhost:14566/ \
    -H "Content-Type: application/x-amz-json-1.1" \
    -H "X-Amz-Target: AWSPriceListService.DescribeServices" \
    -H "Authorization: AWS4-HMAC-SHA256 Credential=AKID/20260101/us-east-1/pricing/aws4_request" \
    -d '{}'
{"FormatVersion":"aws_v1","Services":[
    {"ServiceCode":"AmazonEC2","AttributeNames":[...]},
    {"ServiceCode":"AmazonS3","AttributeNames":[...]},
    {"ServiceCode":"AWSLambda","AttributeNames":[...]}
]}

$ curl -s -X POST http://localhost:14566/ ... GetProducts AmazonEC2/us-east-1
PriceList count: 3

Container logs now show PricingService initializing on first request:

INFO  [io.github.hectorvent.floci.core.common.AwsJson11Controller]
        AwsJson11Controller pricing action: DescribeServices
INFO  [io.github.hectorvent.floci.services.pricing.PricingService]
        Pricing snapshot loaded: 3 services.

That second line was missing in the broken build — load() was returning early on a null classpath read before it could log. With the resource include + class-loader switch, it runs as expected.

@hectorvent
Copy link
Copy Markdown
Collaborator

@ShubhamDX thank you!

@cfranzen Could you take a look at this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants