Skip to main content

Inventory Service

Overview​

The Inventory Service provides product inventory management functionality. It uses Aurora PostgreSQL to store inventory data and resolves concurrency issues through the Reserve/Release pattern. Kafka events are published when inventory changes to integrate with other services.

ItemDetails
LanguageGo 1.21+
FrameworkGin
DatabaseAurora PostgreSQL
CacheElastiCache (Valkey)
Namespacecore-services
Port8080
Health Check/healthz, /readyz

Architecture​

Key Features​

1. Inventory Lookup​

  • SKU-based inventory lookup
  • Provides available quantity, reserved quantity, and total quantity

2. Inventory Reservation (Reserve)​

  • Reserve inventory during order placement
  • Transaction-based concurrency control
  • Returns error when stock is insufficient

3. Inventory Release​

  • Release reservation on order cancellation
  • Release within reserved quantity limits

4. Inventory Update​

  • Direct inventory modification for administrators
  • Upsert support

API Endpoints​

MethodPathDescription
GET/api/v1/inventory/:skuGet inventory
POST/api/v1/inventory/:sku/reserveReserve inventory
POST/api/v1/inventory/:sku/releaseRelease reservation
PUT/api/v1/inventory/:skuUpdate inventory

Get Inventory​

Request​

GET /api/v1/inventory/SGB-PRO-15

Response​

{
"sku": "SGB-PRO-15",
"available": 45,
"reserved": 5,
"total": 50,
"updated_at": "2024-01-15T10:30:00Z"
}

Reserve Inventory​

Request​

POST /api/v1/inventory/SGB-PRO-15/reserve
Content-Type: application/json

{
"quantity": 2
}

Response (Success)​

{
"sku": "SGB-PRO-15",
"available": 43,
"reserved": 7,
"total": 50,
"updated_at": "2024-01-15T10:35:00Z"
}

Response (Insufficient Stock)​

{
"error": "insufficient stock"
}

HTTP Status: 409 Conflict

Release Reservation​

Request​

POST /api/v1/inventory/SGB-PRO-15/release
Content-Type: application/json

{
"quantity": 1
}

Response​

{
"sku": "SGB-PRO-15",
"available": 44,
"reserved": 6,
"total": 50,
"updated_at": "2024-01-15T10:40:00Z"
}

Update Inventory​

Request​

PUT /api/v1/inventory/SGB-PRO-15
Content-Type: application/json

{
"available": 100,
"total": 100
}

Response​

{
"sku": "SGB-PRO-15",
"available": 100,
"reserved": 0,
"total": 100,
"updated_at": "2024-01-15T11:00:00Z"
}

Data Models​

Inventory​

type Inventory struct {
SKU string `json:"sku"`
Available int `json:"available"`
Reserved int `json:"reserved"`
Total int `json:"total"`
UpdatedAt time.Time `json:"updated_at"`
}

ReserveRequest​

type ReserveRequest struct {
Quantity int `json:"quantity" binding:"required,min=1"`
}

ReleaseRequest​

type ReleaseRequest struct {
Quantity int `json:"quantity" binding:"required,min=1"`
}

UpdateStockRequest​

type UpdateStockRequest struct {
Available int `json:"available" binding:"min=0"`
Total int `json:"total" binding:"min=0"`
}

Database Schema​

inventory Table​

CREATE TABLE inventory (
sku VARCHAR(100) PRIMARY KEY,
available INTEGER NOT NULL DEFAULT 0,
reserved INTEGER NOT NULL DEFAULT 0,
total INTEGER NOT NULL DEFAULT 0,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),

CONSTRAINT available_non_negative CHECK (available >= 0),
CONSTRAINT reserved_non_negative CHECK (reserved >= 0),
CONSTRAINT total_equals_sum CHECK (total = available + reserved)
);

CREATE INDEX idx_inventory_updated_at ON inventory(updated_at);

Events (Kafka)​

Published Topics​

TopicDescriptionTrigger
inventory.reservedInventory reservation eventOn Reserve success
inventory.releasedReservation release eventOn Release success
inventory.updatedInventory update eventOn UpdateStock success

Event Payloads​

inventory.reserved​

{
"event": "inventory.reserved",
"sku": "SGB-PRO-15",
"quantity": 2,
"inventory": {
"sku": "SGB-PRO-15",
"available": 43,
"reserved": 7,
"total": 50,
"updated_at": "2024-01-15T10:35:00Z"
}
}

inventory.released​

{
"event": "inventory.released",
"sku": "SGB-PRO-15",
"quantity": 1,
"inventory": {
"sku": "SGB-PRO-15",
"available": 44,
"reserved": 6,
"total": 50,
"updated_at": "2024-01-15T10:40:00Z"
}
}

inventory.updated​

{
"event": "inventory.updated",
"sku": "SGB-PRO-15",
"inventory": {
"sku": "SGB-PRO-15",
"available": 100,
"reserved": 0,
"total": 100,
"updated_at": "2024-01-15T11:00:00Z"
}
}

Environment Variables​

VariableDescriptionDefault
PORTServer port8080
AWS_REGIONAWS regionus-east-1
REGION_ROLERegion role (PRIMARY/SECONDARY)PRIMARY
PRIMARY_HOSTPrimary region host-
DB_HOSTAurora hostlocalhost
DB_PORTAurora port5432
DB_NAMEDatabase nameinventory
DB_USERDatabase usermall
DB_PASSWORDDatabase password-
CACHE_HOSTElastiCache hostlocalhost
CACHE_PORTElastiCache port6379
KAFKA_BROKERSKafka broker addresslocalhost:9092
LOG_LEVELLog levelinfo

Service Dependencies​

Services It Depends On​

ServicePurpose
Aurora PostgreSQLInventory data storage
ElastiCache (Valkey)Caching (optional)
MSK (Kafka)Event publishing

Components That Depend On This Service​

ComponentPurpose
API GatewayInventory API routing
Order ServiceInventory reservation during orders
Payment ServiceInventory confirmation on payment completion
Warehouse ServiceInventory in/out management

Concurrency Control​

Reserve and Release operations use SELECT FOR UPDATE to perform row-level locking.

Insufficient Stock Handling​

if inv.Available < quantity {
return nil, ErrInsufficientStock
}

Returns 409 Conflict response when stock is insufficient.

Multi-Region Behavior​

Aurora Global Database​

The Inventory Service replicates data across regions through Aurora Global Database.

Write Operations​

  • Primary region: Direct write to Aurora Writer
  • Secondary region: Request forwarding to Primary

Read Operations​

  • All regions read from local Aurora Reader

Error Responses​

400 Bad Request​

{
"error": "invalid request body"
}

404 Not Found​

{
"error": "inventory not found"
}

409 Conflict​

{
"error": "insufficient stock"
}

500 Internal Server Error​

{
"error": "internal server error"
}