Skip to main content

Slot Matching

Slot matching is the process by which Prism automatically binds pattern requirements to available backends. This is a key part of Layer 3 (Pattern Selection) and Layer 4 (Backend Binding) in the configuration model.

Automatic Selection

Slot matching is fully automatic. Users declare requirements, and the platform selects the best backend based on capabilities, performance, cost, and availability.

Overview

What is a Slot?

A slot is a capability requirement that a pattern has. Think of it as a socket that needs to be filled by a compatible backend.

Example: The Multicast Registry pattern has two slots:

  • registry slot - Needs key-value storage with watch capability
  • messaging slot - Needs pub/sub messaging

Matching Process

1. Pattern declares slot requirements

2. Platform queries backend registry

3. Filter backends by interface compatibility

4. Filter backends by capability support

5. Filter backends by performance requirements

6. Score remaining candidates

7. Select highest-scoring backend

8. Create slot binding

References:


Slot Requirements

Structure

slot_requirement:
# Slot identity
slot_name: storage

# High-level capabilities needed
capabilities:
- get
- set
- delete
- transaction

# Specific API contracts required
interfaces:
- KeyValueBasicInterface
- TransactionalInterface

# Whether slot is optional
optional: false

# Performance requirements
performance:
min_write_rps: 10000
min_read_rps: 50000
max_latency_p99: 25ms
requires_transactions: true
requires_atomic_writes: true

Common Slots

Slot NameCommon In PatternsTypical Requirements
storageMost patternsGet, Set, Delete operations
registryMulticast RegistryKeyValue + Watch capability
messagingPubSub, QueuePublish, Subscribe
cacheHigh-performance patternsGet, Set with TTL
walDurable patternsAppend-only log
object_storeClaim-checkLarge object storage
query_storeMailbox, SearchComplex query support
graph_storeGraph patternsGraph traversal

Matching Algorithm

Phase 1: Interface Compatibility

Required: Backends MUST implement all required interfaces.

def check_interface_compatibility(slot, backend):
"""Check if backend implements required interfaces."""
for required_interface in slot.interfaces:
if required_interface not in backend.interfaces:
return False, f"Missing interface: {required_interface}"
return True, "All interfaces supported"

Example:

# Slot requires
interfaces:
- KeyValueBasicInterface
- TransactionalInterface

# Backend A implements
interfaces:
- KeyValueBasicInterface
- TransactionalInterface
- TTLInterface
# ✅ MATCH (has all required + extra)

# Backend B implements
interfaces:
- KeyValueBasicInterface
# ❌ NO MATCH (missing TransactionalInterface)

Phase 2: Capability Compatibility

Required: Backends MUST support all required capabilities.

def check_capability_compatibility(slot, backend):
"""Check if backend supports required capabilities."""
for required_capability in slot.capabilities:
if required_capability not in backend.capabilities:
return False, f"Missing capability: {required_capability}"
return True, "All capabilities supported"

Example:

# Slot requires
capabilities:
- get
- set
- transaction

# Backend A supports
capabilities:
- get
- set
- delete
- transaction
# ✅ MATCH (has all required)

# Backend B supports
capabilities:
- get
- set
- delete
# ❌ NO MATCH (missing transaction)

Phase 3: Performance Requirements

Required: Backends MUST meet minimum performance thresholds.

def check_performance_requirements(slot, backend):
"""Check if backend meets performance requirements."""
checks = []

# Write throughput
if backend.capacity.available_write_rps < slot.performance.min_write_rps:
return False, f"Insufficient write capacity: {backend.capacity.available_write_rps} < {slot.performance.min_write_rps}"

# Read throughput
if backend.capacity.available_read_rps < slot.performance.min_read_rps:
return False, f"Insufficient read capacity: {backend.capacity.available_read_rps} < {slot.performance.min_read_rps}"

# Latency
if slot.performance.max_latency_p99:
if backend.performance.latency.p99_ms > parse_latency(slot.performance.max_latency_p99):
return False, f"Latency too high: {backend.performance.latency.p99_ms}ms"

# Transactions
if slot.performance.requires_transactions:
if 'transaction' not in backend.capabilities:
return False, "Transactions required but not supported"

return True, "Performance requirements met"

Example:

# Slot requires
performance:
min_write_rps: 10000
min_read_rps: 50000
max_latency_p99: 25ms

# Backend A capacity
capacity:
available_write_rps: 100000
available_read_rps: 500000
performance:
latency:
p99_ms: 20
# ✅ MATCH (exceeds all requirements)

# Backend B capacity
capacity:
available_write_rps: 5000 # Too low!
available_read_rps: 500000
# ❌ NO MATCH (insufficient write capacity)

Phase 4: Scoring

Objective: Among compatible backends, select the best fit based on multiple factors.

def calculate_match_score(slot, backend):
"""
Calculate match score (0.0 to 1.0).

Weights:
- Performance: 40%
- Cost: 30%
- Availability: 20%
- Region affinity: 10%
"""
score = 0.0

# 1. Performance match (40% weight)
write_ratio = min(backend.capacity.available_write_rps / slot.performance.min_write_rps, 2.0)
read_ratio = min(backend.capacity.available_read_rps / slot.performance.min_read_rps, 2.0)
performance_score = min(write_ratio, read_ratio) / 2.0 # 0.5 to 1.0
score += 0.4 * performance_score

# 2. Cost efficiency (30% weight)
# Lower cost per operation = higher score
avg_cost = (backend.cost.cost_per_1k_writes + backend.cost.cost_per_1k_reads) / 2.0
cost_score = 1.0 / (avg_cost * 1000 + 1.0) # Normalize
score += 0.3 * cost_score

# 3. Availability (20% weight)
availability_score = backend.health.uptime_percent_24h / 100.0
score += 0.2 * availability_score

# 4. Region affinity (10% weight)
if backend.region == slot.preferred_region:
score += 0.1
elif backend.region in slot.acceptable_regions:
score += 0.05

return score

Scoring Example:

# Slot requirement
performance:
min_write_rps: 10000
min_read_rps: 50000
preferred_region: us-east-1

# Backend A
capacity:
available_write_rps: 100000 # 10x required
available_read_rps: 500000 # 10x required
cost:
cost_per_1k_writes: 0.001
cost_per_1k_reads: 0.0005
health:
uptime_percent_24h: 99.95
region: us-east-1

# Score calculation:
# Performance: (10x / 2) / 2 = 1.0 → 0.4 * 1.0 = 0.40
# Cost: 1.0 / (0.00075 * 1000 + 1) = 0.57 → 0.3 * 0.57 = 0.17
# Availability: 99.95 / 100 = 0.9995 → 0.2 * 0.9995 = 0.20
# Region: Match → 0.1
# TOTAL: 0.87

# Backend B
capacity:
available_write_rps: 15000 # 1.5x required
available_read_rps: 75000 # 1.5x required
cost:
cost_per_1k_writes: 0.0001 # 10x cheaper!
cost_per_1k_reads: 0.00005
health:
uptime_percent_24h: 99.50
region: us-west-2

# Score calculation:
# Performance: (1.5x / 2) / 2 = 0.375 → 0.4 * 0.375 = 0.15
# Cost: 1.0 / (0.000075 * 1000 + 1) = 0.93 → 0.3 * 0.93 = 0.28
# Availability: 99.50 / 100 = 0.995 → 0.2 * 0.995 = 0.20
# Region: Different → 0.0
# TOTAL: 0.63

# Backend A wins (0.87 > 0.63)

Match Reasons

When a backend is selected, the platform generates reasons explaining why:

Reason Types

slot_binding:
pattern_id: wal-001
slot_name: storage
backend_id: postgres-primary

reasons:
- type: capability_match
explanation: "Backend implements TransactionalInterface required for WAL"

- type: performance
explanation: "Backend provides 100k write RPS (required: 10k, 10x headroom)"

- type: consistency
explanation: "Backend offers strong consistency (matches durability: strong)"

- type: region_affinity
explanation: "Backend in same region (us-east-1) as requester"

- type: cost
explanation: "Backend has competitive cost ($0.001 per 1k writes)"

Rejection Reasons

When a backend is NOT selected:

alternative:
backend_id: redis-cache
score: 0.45
rejection_reason: "Lower score (0.45) than selected backend (0.87)"
issues:
- "Missing TransactionalInterface"
- "No ACID transaction support"

Advanced Matching

Multi-Slot Patterns

Patterns with multiple slots require coordinated matching:

pattern: multicast-registry

slots:
registry:
capabilities: [get, set, delete, watch]
interfaces: [KeyValueBasicInterface, WatchInterface]
performance:
min_write_rps: 1000
min_read_rps: 10000

messaging:
capabilities: [publish, subscribe]
interfaces: [PubSubInterface]
performance:
min_write_rps: 5000
min_read_rps: 50000

# Matched bindings
slot_bindings:
- slot_name: registry
backend_id: postgres-primary
reasons: [capability_match, watch_support]

- slot_name: messaging
backend_id: kafka-prod
reasons: [capability_match, high_throughput]

Co-Location Optimization

For performance, slots may prefer backends in the same region:

optimization:
prefer_colocation: true
max_latency_between_slots: 5ms

# This may lower individual slot scores but improve overall performance
slot_bindings:
- slot_name: registry
backend_id: postgres-us-east-1 # Score: 0.82
reason: "Co-located with messaging backend"

- slot_name: messaging
backend_id: kafka-us-east-1 # Score: 0.85
reason: "Co-located with registry backend"

# Better than:
# registry: postgres-eu-west-1 (score: 0.90)
# messaging: kafka-us-east-1 (score: 0.85)
# Cross-region latency: 80ms

Fallback Strategies

Capacity Exhaustion

When primary backends are at capacity:

slot: storage
primary_match:
backend_id: postgres-primary
rejection_reason: "Capacity exhausted (100k/100k write RPS used)"

fallback_match:
backend_id: postgres-secondary
score: 0.72
reason: "Fallback to secondary (lower score but available capacity)"

Regional Fallback

When preferred region unavailable:

slot: storage
preferred_region: us-east-1

primary_match:
backend_id: postgres-us-east-1
rejection_reason: "Unhealthy status"

fallback_match:
backend_id: postgres-us-west-2
score: 0.75
reason: "Fallback to different region (same compliance: PCI, SOC2)"

Degraded Mode

When no exact match exists:

slot: storage
required_interfaces:
- KeyValueBasicInterface
- TransactionalInterface

degraded_match:
backend_id: redis-cache
score: 0.60
warnings:
- "Missing TransactionalInterface"
- "No ACID transaction support"
reason: "Degraded mode: Some features unavailable"

Match Validation

Before finalizing a binding, the platform validates:

1. Interface Contract Validation

validation:
slot: storage
backend: postgres-primary

checks:
- interface: KeyValueBasicInterface
operations:
- Get: ✅ Implemented
- Set: ✅ Implemented
- Delete: ✅ Implemented
- Exists: ✅ Implemented

- interface: TransactionalInterface
operations:
- BeginTransaction: ✅ Implemented
- CommitTransaction: ✅ Implemented
- RollbackTransaction: ✅ Implemented

2. Quota Validation

validation:
team: payments-team
current_usage:
total_write_rps: 40000
new_request:
write_rps: 15000
team_quota:
max_total_write_rps: 50000

result: ❌ DENIED
reason: "Would exceed team quota (40k + 15k > 50k)"

3. Compliance Validation

validation:
namespace_requirements:
compliance: [pci, hipaa]
backend_compliance:
backend: postgres-primary
certifications: [pci, soc2, hipaa]

result: ✅ APPROVED
reason: "Backend has all required compliance certifications"

Performance Considerations

Matching Speed

Slot matching must be fast (< 100ms) to avoid blocking namespace creation:

# Optimization strategies:
1. Index backends by interfaces (hash map lookup)
2. Index backends by capabilities (hash map lookup)
3. Pre-calculate backend scores (cache for 5 minutes)
4. Parallel evaluation of candidates
5. Early termination when perfect match found

Caching

match_cache:
key: "{slot_requirements_hash}:{available_backends_hash}"
ttl: 300s # 5 minutes
invalidate_on:
- backend_capacity_change
- backend_health_change
- new_backend_registered

Monitoring

metrics:
- match_duration_ms
- candidates_evaluated
- cache_hit_rate
- match_score_distribution
- rejections_by_reason

Example: Complete Matching Flow

Input

namespace_request:
namespace: order-processing
team: payments-team
pattern: queue
needs:
durability: strong
write_rps: 5000
read_rps: 10000
consistency: strong

Pattern Selection Output

selected_patterns:
- pattern_id: wal-001
pattern_type: wal
slot_requirements:
- slot_name: storage
capabilities: [get, set, delete, transaction]
interfaces: [KeyValueBasicInterface, TransactionalInterface]
performance:
min_write_rps: 5000
min_read_rps: 10000
requires_transactions: true

Backend Query

query:
required_interfaces:
- KeyValueBasicInterface
- TransactionalInterface
required_capabilities:
- transaction
min_capacity:
min_write_rps: 5000
min_read_rps: 10000

Candidates

candidates:
- backend_id: postgres-primary
score: 0.87
interfaces: ✅ All match
capabilities: ✅ All match
performance: ✅ 100k/500k RPS
cost: $0.001 per 1k writes
health: 99.95% uptime
region: us-east-1

- backend_id: postgres-secondary
score: 0.72
interfaces: ✅ All match
capabilities: ✅ All match
performance: ✅ 50k/200k RPS
cost: $0.001 per 1k writes
health: 99.90% uptime
region: us-west-2

- backend_id: mysql-prod
score: 0.68
interfaces: ✅ All match
capabilities: ✅ All match
performance: ⚠️ 20k/100k RPS (lower)
cost: $0.002 per 1k writes (higher)
health: 99.80% uptime
region: us-east-1

Selected Binding

slot_binding:
pattern_id: wal-001
slot_name: storage
backend_id: postgres-primary

reasons:
- type: capability_match
explanation: "Implements TransactionalInterface required for WAL"

- type: performance
explanation: "Provides 100k write RPS (required: 5k, 20x headroom)"

- type: consistency
explanation: "Strong consistency matches durability requirement"

- type: availability
explanation: "99.95% uptime in last 24h"

- type: region_affinity
explanation: "Located in us-east-1 (same as requester)"

slot_config:
connection_pool_size: 20
query_timeout: 5s
retry_policy:
max_attempts: 3

Alternatives Considered

alternatives:
- backend_id: postgres-secondary
score: 0.72
rejection_reason: "Lower score (0.72 vs 0.87)"
notes: "Would be selected if primary unavailable"

- backend_id: mysql-prod
score: 0.68
rejection_reason: "Lower score (0.68 vs 0.87)"
notes: "Lower performance, higher cost"

See Also