β AMCP Best Practices
Production-ready patterns and recommendations
π€ Agent Design Principles
β Single Responsibility
Each agent should have a single, well-defined responsibility.
β Good
// Focused on weather data processing only
public class WeatherProcessorAgent extends Agent {
public void processWeatherData(WeatherData data) {
// Process weather data
}
}
β Avoid
// Too many responsibilities
public class WeatherAgent extends Agent {
public void processWeatherData() { }
public void sendNotifications() { }
public void manageUsers() { }
public void generateReports() { }
}
β Stateless Design
Design agents to be stateless when possible for better scalability.
@Agent("order-processor")
public class OrderProcessorAgent extends Agent {
// Avoid instance variables for state
// Use event payload or external storage instead
@EventHandler
public void processOrder(Event event) {
OrderData order = event.getPayload(OrderData.class);
// Process order without storing state
ProcessedOrder result = processOrderData(order);
// Publish result
publish(Event.builder()
.topic("order.processed")
.payload(result)
.build());
}
}
π‘ Event Design Patterns
Topic Naming Convention
Use hierarchical, descriptive topic names
// Good topic naming
weather.data.raw.london
order.created.ecommerce
user.profile.updated
// Avoid generic names
data
event
message
Event Versioning
Include version information for backward compatibility
Event event = Event.builder()
.topic("order.created.v2")
.payload(orderData)
.metadata("version", "2.0")
.build();
Correlation IDs
Use correlation IDs to track related events
Event response = Event.builder()
.topic("order.processed")
.payload(result)
.correlationId(originalEvent.getCorrelationId())
.build();
β‘ Performance Optimization
π Batch Processing
Process events in batches when possible to improve throughput.
@EventHandler
@BatchSize(100)
@BatchTimeout(5000) // 5 seconds
public void processBatchedEvents(List<Event> events) {
// Process events in batch
List<ProcessedData> results = events.stream()
.map(this::processEvent)
.collect(Collectors.toList());
// Publish batch results
publishBatch(results);
}
π§΅ Async Processing
Use asynchronous processing for non-blocking operations.
@EventHandler
public void handleEvent(Event event) {
// Quick validation
if (!isValidEvent(event)) {
return;
}
// Async processing
CompletableFuture.supplyAsync(() -> {
return heavyProcessing(event);
}).thenAccept(result -> {
publishResult(result);
});
}
πΎ Caching Strategy
Implement intelligent caching for frequently accessed data.
@Agent("data-service")
public class DataServiceAgent extends Agent {
private final Cache<String, Data> cache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
@EventHandler
public void handleDataRequest(Event event) {
String key = event.getPayload(String.class);
Data data = cache.get(key, () -> {
return expensiveDataLookup(key);
});
publishData(data);
}
}
π Security Best Practices
π Authentication
Always authenticate agents before allowing mesh participation.
@Agent("secure-agent")
@RequireAuthentication
public class SecureAgent extends Agent {
@Override
public void onActivation() {
// Agent automatically authenticated before activation
subscribe("secure.data.*");
}
}
π‘οΈ Input Validation
Validate all incoming event data to prevent injection attacks.
@EventHandler
public void handleUserInput(Event event) {
UserInput input = event.getPayload(UserInput.class);
// Validate input
if (!inputValidator.isValid(input)) {
publishError("Invalid input received");
return;
}
// Sanitize input
UserInput sanitized = inputSanitizer.sanitize(input);
processInput(sanitized);
}
π Topic Permissions
Implement topic-level access control.
@Agent("financial-agent")
@TopicPermissions({
@Permission(topic = "financial.data.*", access = READ_WRITE),
@Permission(topic = "public.data.*", access = READ_ONLY)
})
public class FinancialAgent extends Agent {
// Agent can only access permitted topics
}
π Monitoring & Observability
π Metrics Collection
Collect key performance metrics for monitoring.
@Agent("monitored-agent")
public class MonitoredAgent extends Agent {
private final MeterRegistry meterRegistry;
private final Counter eventCounter;
private final Timer processingTimer;
@EventHandler
public void handleEvent(Event event) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
processEvent(event);
eventCounter.increment("success");
} catch (Exception e) {
eventCounter.increment("error");
throw e;
} finally {
sample.stop(processingTimer);
}
}
}
π Structured Logging
Use structured logging for better observability.
@EventHandler
public void processOrder(Event event) {
String orderId = event.getMetadata("orderId");
log.info("Processing order",
kv("orderId", orderId),
kv("agentId", getAgentId()),
kv("timestamp", Instant.now()));
try {
// Process order
log.info("Order processed successfully",
kv("orderId", orderId));
} catch (Exception e) {
log.error("Order processing failed",
kv("orderId", orderId),
kv("error", e.getMessage()));
}
}
π¨ Health Checks
Implement comprehensive health checks.
@Agent("health-monitored-agent")
public class HealthMonitoredAgent extends Agent implements HealthIndicator {
@Override
public Health health() {
return Health.up()
.withDetail("activeConnections", getActiveConnections())
.withDetail("lastEventTime", getLastEventTime())
.withDetail("errorRate", getErrorRate())
.build();
}
@Scheduled(fixedRate = 30000) // Every 30 seconds
public void publishHealthStatus() {
Health health = health();
publish(Event.builder()
.topic("agent.health." + getAgentId())
.payload(health)
.build());
}
}
π Deployment Best Practices
π³ Containerization
Use Docker for consistent deployments across environments.
# Dockerfile
FROM openjdk:17-jre-slim
COPY target/my-agent-1.0.jar /app/agent.jar
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["java", "-jar", "/app/agent.jar"]
βΈοΈ Kubernetes Deployment
Use Kubernetes for orchestration and scaling.
apiVersion: apps/v1
kind: Deployment
metadata:
name: weather-agent
spec:
replicas: 3
selector:
matchLabels:
app: weather-agent
template:
metadata:
labels:
app: weather-agent
spec:
containers:
- name: weather-agent
image: amcp/weather-agent:1.5.0
ports:
- containerPort: 8080
env:
- name: AMCP_BROKER_URL
value: "kafka:9092"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
π Blue-Green Deployment
Implement zero-downtime deployments.
# Blue-Green deployment strategy
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: weather-agent-rollout
spec:
replicas: 5
strategy:
blueGreen:
activeService: weather-agent-active
previewService: weather-agent-preview
autoPromotionEnabled: false
scaleDownDelaySeconds: 30
prePromotionAnalysis:
templates:
- templateName: success-rate
args:
- name: service-name
value: weather-agent-preview
selector:
matchLabels:
app: weather-agent
template:
metadata:
labels:
app: weather-agent
spec:
containers:
- name: weather-agent
image: amcp/weather-agent:1.5.0