Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
- inventory
- membership
- pricing
- shipping
runs-on: depot-ubuntu-24.04-8
steps:
- name: Store new version in env
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PROJECT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
# Apps that have a Docker image (build + dev-deploy)
APPS = coupon currency frontend geolocation inventory membership pricing load-generator
APPS = coupon currency frontend geolocation inventory membership pricing shipping load-generator
# All apps that produce Linux packages (includes demo meta-package)
PACKAGE_APPS = $(APPS) demo

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Simple Demo contains the following services:
| Inventory | Python | 3.11 |
| Membership | Go | 1.21 |
| Pricing | .NET | 8.0 |
| Shipping | C++ | 17 (GCC) |

## Running locally

Expand Down
4 changes: 2 additions & 2 deletions demo/distribution/systemd.service
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ After=network.target
Type=oneshot
RemainAfterExit=yes
# Start: all demo services except load-generator (load-generator stays disabled by default)
ExecStart=/bin/sh -c 'systemctl start odigos-demo-membership.service odigos-demo-pricing.service odigos-demo-currency.service odigos-demo-frontend.service odigos-demo-geolocation.service odigos-demo-inventory.service odigos-demo-coupon.service 2>/dev/null || true'
ExecStart=/bin/sh -c 'systemctl start odigos-demo-membership.service odigos-demo-pricing.service odigos-demo-currency.service odigos-demo-frontend.service odigos-demo-geolocation.service odigos-demo-inventory.service odigos-demo-coupon.service odigos-demo-shipping.service 2>/dev/null || true'
# Stop: all demo services including load-generator
ExecStop=/bin/sh -c 'systemctl stop odigos-demo-load-generator.service odigos-demo-membership.service odigos-demo-pricing.service odigos-demo-currency.service odigos-demo-frontend.service odigos-demo-geolocation.service odigos-demo-inventory.service odigos-demo-coupon.service 2>/dev/null || true'
ExecStop=/bin/sh -c 'systemctl stop odigos-demo-load-generator.service odigos-demo-membership.service odigos-demo-pricing.service odigos-demo-currency.service odigos-demo-frontend.service odigos-demo-geolocation.service odigos-demo-inventory.service odigos-demo-coupon.service odigos-demo-shipping.service 2>/dev/null || true'

[Install]
WantedBy=multi-user.target
4 changes: 3 additions & 1 deletion demo/nfpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ vendor: Odigos
homepage: https://odigos.io
description: |
Meta-package that installs all Odigos demo applications (membership, pricing,
currency, frontend, geolocation, inventory, coupon, load-generator).
currency, frontend, geolocation, inventory, coupon, shipping, load-generator).
systemctl start odigos-demo → start all services except load-generator
systemctl stop odigos-demo → stop all services including load-generator
depends:
Expand All @@ -22,6 +22,7 @@ depends:
- odigos-demo-geolocation (= ${VERSION})
- odigos-demo-inventory (= ${VERSION})
- odigos-demo-coupon (= ${VERSION})
- odigos-demo-shipping (= ${VERSION})
- odigos-demo-load-generator (= ${VERSION})
contents:
- src: distribution/systemd.service
Expand All @@ -39,4 +40,5 @@ overrides:
- "odigos-demo-geolocation = ${VERSION}"
- "odigos-demo-inventory = ${VERSION}"
- "odigos-demo-coupon = ${VERSION}"
- "odigos-demo-shipping = ${VERSION}"
- "odigos-demo-load-generator = ${VERSION}"
8 changes: 8 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ services:
COUPON_SERVICE_HOST: coupon:8084
CURRENCY_SERVICE_HOST: nginx:8085
GEOLOCATION_SERVICE_HOST: geolocation:8086
SHIPPING_SERVICE_HOST: shipping:8087
membership:
build:
context: ./membership
Expand Down Expand Up @@ -87,3 +88,10 @@ services:
environment:
PORT: 8086
RAILS_MASTER_KEY: df0300c20246e24d331787f6540a72fa
shipping:
build:
context: ./shipping
ports:
- '8087:8087'
environment:
PORT: 8087
2 changes: 2 additions & 0 deletions frontend/deployment/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ spec:
value: currency:8080
- name: GEOLOCATION_SERVICE_HOST
value: geolocation:8080
- name: SHIPPING_SERVICE_HOST
value: shipping:8080
ports:
- containerPort: 8080
1 change: 1 addition & 0 deletions frontend/distribution/systemd.service
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Environment="PRICING_SERVICE_HOST=localhost:8083"
Environment="COUPON_SERVICE_HOST=localhost:8084"
Environment="CURRENCY_SERVICE_HOST=localhost:8085"
Environment="GEOLOCATION_SERVICE_HOST=localhost:8086"
Environment="SHIPPING_SERVICE_HOST=localhost:8087"

[Install]
WantedBy=multi-user.target
11 changes: 11 additions & 0 deletions frontend/src/main/java/dev/keyval/kvshop/frontend/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ public class Product {
private String name;
private double price;
private String image;
private int shippingCents;

public Product() {
this.id = 0;
this.name = "";
this.price = 0.0;
this.image = "";
this.shippingCents = 0;
}
public Product(int id, String name, double price, String image) {
this.id = id;
this.name = name;
this.price = price;
this.image = image;
this.shippingCents = 0;
}

public int getId() {
Expand Down Expand Up @@ -50,4 +53,12 @@ public String getImage() {
public void setImage(String image) {
this.image = image;
}

public int getShippingCents() {
return shippingCents;
}

public void setShippingCents(int shippingCents) {
this.shippingCents = shippingCents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@ public class ProductController {
private final InventoryService inventoryService;
private final PricingService pricingService;
private final CouponService couponService;
private final ShippingService shippingService;

@Autowired
public ProductController(
CurrencyService currencyService,
GeoService geoService,
InventoryService inventoryService,
PricingService pricingService,
CouponService couponService) {
CouponService couponService,
ShippingService shippingService) {
this.currencyService = currencyService;
this.geoService = geoService;
this.inventoryService = inventoryService;
this.pricingService = pricingService;
this.couponService = couponService;
this.shippingService = shippingService;
}

@CrossOrigin(origins = "*")
Expand All @@ -44,9 +47,13 @@ public String getConversionRate(@PathVariable String currencyPair) {
public List<Product> getProducts() {
List<Product> products = this.inventoryService.getInventory();

// Add price to every product
// Add price and shipping quote to every product
for (Product product : products) {
product.setPrice(this.pricingService.getPrice(product.getId()));
ShippingQuoteResult quote = this.shippingService.getQuote(product.getId());
if (quote != null) {
product.setShippingCents(quote.getShippingCents());
}
}

// Get coupons
Expand All @@ -66,6 +73,12 @@ public void buyProduct(@RequestParam(name = "id") int id) {
// Validate price via pricing service
double price = this.pricingService.getPrice(id);

ShippingQuoteResult shipping = this.shippingService.getQuote(id);
if (shipping != null) {
System.out.println("Shipping quote for buy id " + id + ": " + shipping.getShippingCents()
+ " cents via " + shipping.getCarrier());
}

String currencyPair = "usd-eur";
CurrencyResult currencyInfo = this.currencyService.getCurrencyInfo(currencyPair);
int conversionRate = currencyInfo.getConversionRate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dev.keyval.kvshop.frontend;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ShippingQuoteResult {
@JsonProperty("productId")
private int productId;

@JsonProperty("shippingCents")
private int shippingCents;

@JsonProperty("carrier")
private String carrier;

public ShippingQuoteResult() {}

public int getProductId() {
return productId;
}

public void setProductId(int productId) {
this.productId = productId;
}

public int getShippingCents() {
return shippingCents;
}

public void setShippingCents(int shippingCents) {
this.shippingCents = shippingCents;
}

public String getCarrier() {
return carrier;
}

public void setCarrier(String carrier) {
this.carrier = carrier;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.keyval.kvshop.frontend;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ShippingService {
private final String shippingServiceHost;
private static final Logger log = LoggerFactory.getLogger(ShippingService.class);

public ShippingService(@Value("${SHIPPING_SERVICE_HOST}") String shippingServiceHost) {
this.shippingServiceHost = shippingServiceHost;
}

public ShippingQuoteResult getQuote(int productId) {
String url = "http://" + shippingServiceHost + "/quote?id=" + productId;
ShippingQuoteResult res = new RestTemplate().getForObject(url, ShippingQuoteResult.class);
log.info("Shipping quote for product {}: {} cents ({})", productId,
res != null ? res.getShippingCents() : -1,
res != null ? res.getCarrier() : "n/a");
return res;
}
}
3 changes: 3 additions & 0 deletions frontend/webapp/components/ProductCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const ProductCard = ({ product }) => {
<img src={product.image} alt={product.name} className="h-15 w-15" />
<h3 className="text-lg font-semibold my-2">{product.name}</h3>
<p className="text-gray-600">${product.price}</p>
{product.shippingCents != null && product.shippingCents > 0 && (
<p className="text-gray-500 text-sm">Shipping: ${(product.shippingCents / 100).toFixed(2)}</p>
)}
<button
className={`${green ? 'bg-green-500' : 'bg-blue-500'} hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded mt-2`}
onClick={() => {
Expand Down
1 change: 1 addition & 0 deletions frontend/webapp/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Product = {
name: string
price: number
image: string
shippingCents?: number
}

export default function Home() {
Expand Down
43 changes: 43 additions & 0 deletions kubernetes/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ spec:
value: currency:8080
- name: GEOLOCATION_SERVICE_HOST
value: geolocation:8080
- name: SHIPPING_SERVICE_HOST
value: shipping:8080
ports:
- containerPort: 8080
---
Expand All @@ -188,6 +190,47 @@ spec:
port: 8080
targetPort: 8080

---
##################################################
# Shipping (C++)
##################################################
apiVersion: apps/v1
kind: Deployment
metadata:
name: shipping
labels:
app: shipping
spec:
selector:
matchLabels:
app: shipping
template:
metadata:
labels:
app: shipping
spec:
containers:
- name: shipping
image: registry.odigos.io/odigos-demo-shipping:v0.1.35
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
---
kind: Service
apiVersion: v1
metadata:
name: shipping
spec:
selector:
app: shipping
ports:
- protocol: TCP
port: 8080
targetPort: 8080

---
##################################################
# Geolocation (Ruby on Rails)
Expand Down
11 changes: 11 additions & 0 deletions kubernetes/instrument-all.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,14 @@ spec:
kind: Deployment
name: pricing
namespace: default
---
apiVersion: odigos.io/v1alpha1
kind: Source
metadata:
name: shipping
namespace: default
spec:
workload:
kind: Deployment
name: shipping
namespace: default
7 changes: 7 additions & 0 deletions shipping/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Exclude build artifacts from Docker context
bin
dist
.build
.git
.gitignore
.idea
1 change: 1 addition & 0 deletions shipping/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.build/
41 changes: 41 additions & 0 deletions shipping/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# --- Build nfpm binary (for package stage) ---
FROM golang:1.22-alpine AS nfpm-build
RUN go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.34.0

# --- Build C++ binary (cpp-httplib is header-only, vendored in third_party/) ---
FROM debian:bookworm-slim AS cpp-builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends g++ \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
COPY main.cpp .
COPY third_party ./third_party
RUN g++ -std=c++17 -O2 -pthread -Wall -Wextra -o /workspace/shipping main.cpp

# --- Runtime image ---
FROM debian:bookworm-slim AS app
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --uid 15000 --no-create-home --shell /usr/sbin/nologin appuser
COPY --from=cpp-builder /workspace/shipping /shipping
USER 15000
ENTRYPOINT ["/shipping"]

# --- Package stage ---
FROM debian:bookworm-slim AS package
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=nfpm-build /go/bin/nfpm /usr/local/bin/nfpm
WORKDIR /workspace
COPY distribution ./distribution
COPY nfpm.yaml ./
RUN mkdir -p dist/app /packages
COPY --from=cpp-builder /workspace/shipping dist/app/odigos-demo-shipping
ARG TARGETARCH
ARG VERSION=dev
ENV TARGETARCH=$TARGETARCH
ENV VERSION=$VERSION
RUN nfpm pkg --packager rpm --target /packages && nfpm pkg --packager deb --target /packages
CMD ["true"]
Loading
Loading