Skip to content

Microservices Architecture

Learn how to use UUID-Forge effectively in microservices architectures for consistent entity identification across services.

Overview

In microservices architectures, UUID-Forge solves the critical problem of consistent entity identification across distributed services. By generating deterministic UUIDs, different services can independently create the same UUID for the same entity, eliminating the need for centralized ID generation or complex coordination.

Key Benefits

  • Service Independence: Services can generate UUIDs without inter-service communication
  • Data Consistency: Same entity gets same UUID across all services
  • Event Sourcing: Consistent UUIDs for event correlation
  • Testing: Predictable UUIDs simplify integration testing

Service Design Patterns

1. Namespace-per-Service Pattern

Each service uses its own namespace for entity isolation:

# User Service
from uuid_forge import UUIDGenerator, IDConfig, Namespace
import os

# Service-specific namespace and configuration
user_config = IDConfig(
    namespace=Namespace("user-service.mycompany.com"),
    salt=os.getenv("UUID_FORGE_SALT")
)
user_forge = UUIDGenerator(config=user_config)

class UserService:
    def create_user(self, email, name):
        # Generate deterministic user ID from email
        user_id = user_forge.generate(
            "user",
            email=email.lower().strip()
        )
        return {"id": user_id, "email": email, "name": name}
# Order Service
from uuid_forge import UUIDGenerator, IDConfig, Namespace
import os

order_config = IDConfig(
    namespace=Namespace("order-service.mycompany.com"),
    salt=os.getenv("UUID_FORGE_SALT")
)
order_forge = UUIDGenerator(config=order_config)

# Shared user generator to create consistent user references
user_forge = UUIDGenerator(config=user_config)

class OrderService:
    def create_order(self, user_email, items):
        # Generate consistent user reference (same as User Service!)
        user_id = user_forge.generate(
            "user",
            email=user_email.lower().strip()
        )

        # Generate order ID
        order_id = order_forge.generate(
            "order",
            user_email=user_email.lower().strip(),
            items=tuple(sorted(items))  # Use tuple for hashability
        )

        return {"id": order_id, "user_id": user_id, "items": items}

2. Entity-Type-Based Namespaces

Create namespaces based on entity types for organizational consistency:

from uuid_forge import UUIDGenerator, IDConfig, Namespace
import os

# Entity-specific namespaces under your organization's domain
USERS_NS = Namespace("users.mycompany.com")
ORDERS_NS = Namespace("orders.mycompany.com")
PRODUCTS_NS = Namespace("products.mycompany.com")

# Shared configuration with salt
salt = os.getenv("UUID_FORGE_SALT")

# Shared generator instances with their respective namespaces
user_forge = UUIDGenerator(config=IDConfig(namespace=USERS_NS, salt=salt))
order_forge = UUIDGenerator(config=IDConfig(namespace=ORDERS_NS, salt=salt))
product_forge = UUIDGenerator(config=IDConfig(namespace=PRODUCTS_NS, salt=salt))

# Any service can generate consistent entity UUIDs
def get_user_uuid(email: str):
    return user_forge.generate("user", email=email.lower().strip())

def get_product_uuid(sku: str):
    return product_forge.generate("product", sku=sku.upper().strip())

def get_order_uuid(user_email: str, timestamp: int):
    return order_forge.generate("order", user_email=user_email.lower(), timestamp=timestamp)

Service Integration Examples

User Management Service

from datetime import datetime
from uuid_forge import UUIDGenerator, IDConfig, Namespace
import os

class UserManagementService:
    def __init__(self):
        config = IDConfig(
            namespace=Namespace("users.mycompany.com"),
            salt=os.getenv("UUID_FORGE_SALT")
        )
        self.user_forge = UUIDGenerator(config=config)

    def register_user(self, email, profile_data):
        # Generate deterministic user ID from email
        user_id = self.user_forge.generate("user", email=email.lower().strip())

        user = {
            "id": user_id,
            "email": email,
            "profile": profile_data,
            "created_at": datetime.utcnow()
        }

        # Store in database
        self.db.users.insert(user)

        # Publish event
        self.event_bus.publish("user.registered", {
            "user_id": user_id,
            "email": email
        })

        return user

    def get_user_id(self, email):
        """Other services can call this to get consistent user ID"""
        return self.user_forge.generate("user", email=email.lower().strip())

Order Processing Service

class OrderProcessingService:
    def __init__(self):
        salt = os.getenv("UUID_FORGE_SALT")
        self.user_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("users.mycompany.com"), salt=salt)
        )
        self.order_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("orders.mycompany.com"), salt=salt)
        )
        self.product_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("products.mycompany.com"), salt=salt)
        )

    def create_order(self, user_email, product_skus, quantities):
        # Generate consistent user ID (same as User Service would generate!)
        user_id = self.user_forge.generate("user", email=user_email.lower().strip())

        order_items = []
        for sku, qty in zip(product_skus, quantities):
            product_id = self.product_forge.generate("product", sku=sku.upper().strip())
            order_items.append({
                "product_id": product_id,
                "sku": sku,
                "quantity": qty
            })

        # Generate order ID from business data
        # Use tuple of SKUs for deterministic ordering
        skus_tuple = tuple(sorted(product_skus))
        order_id = self.order_forge.generate(
            "order",
            user_email=user_email.lower().strip(),
            skus=skus_tuple,
            timestamp=datetime.utcnow().isoformat()
        )

        order = {
            "id": order_id,
            "user_id": user_id,
            "items": order_items,
            "status": "pending",
            "created_at": datetime.utcnow()
        }

        # Store order
        self.db.orders.insert(order)

        # Publish event
        self.event_bus.publish("order.created", {
            "order_id": order_id,
            "user_id": user_id
        })

        return order

Notification Service

class NotificationService:
    def __init__(self):
        salt = os.getenv("UUID_FORGE_SALT")
        self.user_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("users.mycompany.com"), salt=salt)
        )
        self.notification_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("notifications.mycompany.com"), salt=salt)
        )

    def handle_order_created(self, event_data):
        user_id = event_data["user_id"]
        order_id = event_data["order_id"]

        # Generate notification ID from business data
        notification_id = self.notification_forge.generate(
            "notification",
            user_id=str(user_id),
            notification_type="order_confirmation",
            reference_id=str(order_id)
        )

        notification = {
            "id": notification_id,
            "user_id": user_id,
            "type": "order_confirmation",
            "message": f"Your order {order_id} has been created",
            "created_at": datetime.utcnow()
        }

        self.send_notification(notification)

Event-Driven Architecture

Event Correlation

Use deterministic UUIDs for event correlation:

class EventService:
    def __init__(self):
        config = IDConfig(
            namespace=Namespace("events.mycompany.com"),
            salt=os.getenv("UUID_FORGE_SALT")
        )
        self.event_forge = UUIDGenerator(config=config)

    def create_correlation_id(self, user_id, action, timestamp):
        """Create deterministic correlation ID for event tracing"""
        return self.event_forge.generate(
            "correlation",
            user_id=str(user_id),
            action=action,
            timestamp=timestamp.isoformat()
        )

    def publish_correlated_events(self, user_id, action):
        timestamp = datetime.utcnow()
        correlation_id = self.create_correlation_id(user_id, action, timestamp)

        events = [
            {"type": "action.started", "correlation_id": correlation_id},
            {"type": "action.processed", "correlation_id": correlation_id},
            {"type": "action.completed", "correlation_id": correlation_id}
        ]

        for event in events:
            self.event_bus.publish(event["type"], event)

Saga Pattern Implementation

class SagaOrchestrator:
    def __init__(self):
        salt = os.getenv("UUID_FORGE_SALT")
        self.saga_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("sagas.mycompany.com"), salt=salt)
        )
        self.user_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("users.mycompany.com"), salt=salt)
        )
        self.order_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("orders.mycompany.com"), salt=salt)
        )

    def start_order_saga(self, user_email, product_skus, timestamp):
        user_id = self.user_forge.generate("user", email=user_email.lower().strip())
        order_id = self.order_forge.generate(
            "order",
            user_email=user_email.lower().strip(),
            skus=tuple(sorted(product_skus)),
            timestamp=timestamp
        )

        # Generate deterministic saga ID
        saga_id = self.saga_forge.generate(
            "order_saga",
            user_id=str(user_id),
            order_id=str(order_id)
        )

        saga_state = {
            "saga_id": saga_id,
            "user_id": user_id,
            "order_id": order_id,
            "steps": ["validate_user", "reserve_inventory", "process_payment"],
            "current_step": 0,
            "status": "started"
        }

        self.execute_saga_step(saga_state)
        return saga_id

API Gateway Integration

Request Tracing

class APIGateway:
    def __init__(self):
        config = IDConfig(
            namespace=Namespace("traces.mycompany.com"),
            salt=os.getenv("UUID_FORGE_SALT")
        )
        self.trace_forge = UUIDGenerator(config=config)

    def create_trace_id(self, request):
        """Create deterministic trace ID for request tracking"""
        return self.trace_forge.generate(
            "trace",
            method=request.method,
            path=request.path,
            user_agent=request.headers.get("User-Agent", ""),
            timestamp=datetime.utcnow().replace(microsecond=0).isoformat()
        )

    def process_request(self, request):
        trace_id = self.create_trace_id(request)
        request.headers["X-Trace-ID"] = str(trace_id)
        return self.forward_to_service(request)

Database Consistency

Cross-Service Queries

class ReportingService:
    def __init__(self):
        salt = os.getenv("UUID_FORGE_SALT")
        self.user_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("users.mycompany.com"), salt=salt)
        )
        self.order_forge = UUIDGenerator(
            config=IDConfig(namespace=Namespace("orders.mycompany.com"), salt=salt)
        )

    def generate_user_order_report(self, user_email):
        # Generate consistent user ID (same as User Service)
        user_id = self.user_forge.generate("user", email=user_email.lower().strip())

        # Query user data from user service database
        user_data = self.user_db.find_one({"id": user_id})

        # Query order data from order service database
        orders = self.order_db.find({"user_id": user_id})

        return {
            "user": user_data,
            "orders": list(orders),
            "generated_at": datetime.utcnow()
        }

Testing Strategies

Integration Testing

class IntegrationTestSuite:
    def setUp(self):
        self.user_service = UserManagementService()
        self.order_service = OrderProcessingService()
        self.notification_service = NotificationService()

    def test_cross_service_uuid_consistency(self):
        """Test that all services generate same UUID for same entity"""
        email = "test@example.com"

        # Generate user ID from different services
        user_id_1 = self.user_service.get_user_id(email)
        user_id_2 = self.order_service.user_forge.generate("user", email=email.lower().strip())
        user_id_3 = self.notification_service.user_forge.generate("user", email=email.lower().strip())

        # All should be identical
        assert user_id_1 == user_id_2 == user_id_3

    def test_end_to_end_workflow(self):
        """Test complete workflow with consistent UUIDs"""
        email = "customer@example.com"

        # Register user
        user = self.user_service.register_user(email, {"name": "Test User"})

        # Create order
        order = self.order_service.create_order(email, ["SKU001"], [1])

        # Verify same user ID is used
        assert user["id"] == order["user_id"]

Monitoring and Observability

UUID Tracking

import logging
from uuid_forge import UUIDGenerator, IDConfig, Namespace

# Define namespace constant
USERS_NS = Namespace("microservices.myapp.com/users")

class UUIDTracker:
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        config = IDConfig(namespace=USERS_NS, salt="v1")
        self.user_forge = UUIDGenerator(config)

    def track_uuid_usage(self, service_name, entity_type, input_data, uuid_result):
        """Track UUID generation for debugging and monitoring"""
        self.logger.info({
            "event": "uuid_generated",
            "service": service_name,
            "entity_type": entity_type,
            "uuid": uuid_result,
            "input_hash": hash(str(input_data))  # Don't log sensitive data
        })

    def validate_uuid_consistency(self, expected_uuid, input_data):
        """Validate that UUID generation is still consistent"""
        generated_uuid = self.user_forge.generate(input_data)
        if generated_uuid != expected_uuid:
            self.logger.error({
                "event": "uuid_inconsistency_detected",
                "expected": expected_uuid,
                "generated": generated_uuid,
                "input_hash": hash(str(input_data))
            })
            return False
        return True

Next Steps