12 KiB
Notifier Service Client Integration Prompt
Use this prompt with Claude or another AI assistant when building a client application that integrates with the Notifier service.
Prompt for AI Assistant
I need to build a client application that integrates with a notification service using gRPC. Please help me implement a production-ready client that follows best practices for performance, security, and reliability.
Service Details
Protocol: gRPC (HTTP/2)
Service Address: notifier-grpc:50051 (Kubernetes internal DNS)
Authentication: API Key via gRPC metadata
API Key Format: nk_ prefix followed by 64 hex characters (e.g., nk_abc123...)
Authentication Requirements
-
API Key Delivery:
- Send API key in gRPC metadata with EVERY request
- Two accepted header formats:
authorization: Bearer nk_your_api_key_here(preferred)x-api-key: nk_your_api_key_here
-
Per-Request Authentication:
- The service validates the API key on every RPC call
- Authentication is NOT done at connection time
- This means you can (and should) use long-lived connections
-
Rate Limiting:
- Rate limits are enforced per API key
- Default: 100 requests per minute (configurable per key)
- Rate limit exceeded returns:
codes.ResourceExhausted - Implement exponential backoff retry for rate limit errors
-
Credential Management:
- Load API key from environment variable:
NOTIFIER_API_KEY - NEVER hardcode API keys in source code
- NEVER log the full API key (mask it:
nk_abc...xyz) - Store in Kubernetes Secret if deploying to k8s
- Load API key from environment variable:
Connection Management Requirements
CRITICAL: Use long-lived gRPC connections for optimal performance.
-
Connection Lifecycle:
- Create ONE connection at application startup
- Reuse the connection for ALL requests
- Close the connection only when application exits
- Do NOT create a new connection for each request
-
Keepalive Configuration:
- Configure client keepalive to prevent connection timeouts
- Recommended settings:
- Time: 10 seconds (ping every 10s of inactivity)
- Timeout: 3 seconds (wait for ping response)
- PermitWithoutStream: true (allow pings when idle)
-
Why This Matters:
- Connection reuse: 10x faster (1.5ms vs 15ms per request)
- Eliminates TCP + TLS handshake overhead (10-15ms per request)
- HTTP/2 multiplexing: handle multiple concurrent requests on one connection
- Lower resource usage: one connection vs thousands
Error Handling Requirements
-
Handle These Error Codes:
codes.Unauthenticated- Invalid or missing API key → Log error, don't retrycodes.ResourceExhausted- Rate limit exceeded → Retry with exponential backoffcodes.InvalidArgument- Bad request payload → Log error, don't retrycodes.Unavailable- Service temporarily unavailable → Retry with backoffcodes.DeadlineExceeded- Request timeout → Retry (may be transient)
-
Retry Strategy:
- Implement exponential backoff: 100ms, 200ms, 400ms, 800ms
- Maximum 3-5 retry attempts for retryable errors
- Only retry: rate limits, unavailable, deadline exceeded
- Do NOT retry: authentication errors, invalid arguments
-
Context Timeouts:
- Set reasonable timeout for each request (5-30 seconds)
- Use
context.WithTimeout()for every RPC call - Allow timeout to be configurable
Code Structure Requirements
-
Client Structure:
NotifierClient struct: - conn: *grpc.ClientConn (long-lived) - client: pb.NotifierServiceClient - apiKey: string (loaded from env) - logger: logging interface -
Required Methods:
NewNotifierClient(address, apiKey string) (*NotifierClient, error)- InitializeSendNotification(ctx, request) (response, error)- Send single notificationSendBatchNotifications(ctx, requests) (responses, error)- Send batchHealthCheck(ctx) error- Verify connection healthClose() error- Clean up connection
-
Initialization Pattern:
- Create client as singleton at application startup
- Use
sync.Onceto ensure only one instance - Defer
Close()in main() to ensure cleanup
Observability Requirements
-
Logging:
- Log connection establishment (info level)
- Log authentication failures (warn level)
- Log rate limit exceeded (warn level)
- Log successful sends (debug level)
- NEVER log the full API key (mask it)
-
Metrics (if using Prometheus):
- Counter:
notifier_requests_total(labels: status, method) - Counter:
notifier_requests_failed_total(labels: error_code) - Histogram:
notifier_request_duration_seconds - Counter:
notifier_rate_limit_errors_total
- Counter:
-
Health Checks:
- Implement background health check goroutine
- Check every 30-60 seconds
- Call the service's HealthCheck RPC
- Log warnings if health checks fail
Security Requirements
-
Credential Security:
- Load API key ONLY from environment variables
- Never commit API keys to version control
- Use
.gitignoreto exclude any files with credentials - Implement a
String()method that masks the API key for logging
-
TLS Configuration:
- For local development:
grpc.WithInsecure()is acceptable - For production: Use TLS with proper certificate validation
- For Kubernetes: Internal communication may use insecure (cluster network is trusted)
- For local development:
-
Graceful Degradation:
- If notifier service is unavailable, application should continue
- Log notification failures but don't crash the application
- Consider implementing a circuit breaker pattern for resilience
Testing Requirements
-
Unit Tests:
- Mock the gRPC client interface
- Test retry logic with rate limit errors
- Test context timeout handling
- Test credential masking in logs
-
Integration Tests:
- Test actual connection to notifier service (if available)
- Test authentication with valid and invalid keys
- Test rate limiting behavior
Kubernetes Deployment Requirements (if applicable)
-
Environment Variables:
env: - name: NOTIFIER_API_KEY valueFrom: secretKeyRef: name: notifier-credentials key: api-key - name: NOTIFIER_ADDRESS value: "notifier-grpc:50051" -
Secrets Configuration:
apiVersion: v1 kind: Secret metadata: name: notifier-credentials type: Opaque stringData: api-key: nk_your_actual_api_key_here
Available gRPC Methods
The NotifierService provides these RPC methods:
-
SendNotification - Send a single notification
- Request:
SendNotificationRequest - Response:
SendNotificationResponse(contains notification_id)
- Request:
-
SendBatchNotifications - Send multiple notifications at once
- Request:
SendBatchNotificationsRequest - Response:
SendBatchNotificationsResponse(contains notification_ids)
- Request:
-
GetNotification - Retrieve notification status by ID
- Request:
GetNotificationRequest(notification_id) - Response:
GetNotificationResponse
- Request:
-
ListNotifications - List recent notifications
- Request:
ListNotificationsRequest(pagination) - Response:
ListNotificationsResponse
- Request:
-
CancelNotification - Cancel a pending notification
- Request:
CancelNotificationRequest(notification_id) - Response:
CancelNotificationResponse
- Request:
-
RetryNotification - Retry a failed notification
- Request:
RetryNotificationRequest(notification_id) - Response:
RetryNotificationResponse
- Request:
-
GetStats - Get service statistics
- Request:
GetStatsRequest - Response:
GetStatsResponse
- Request:
-
GetNotifiers - List available notifier types and accounts
- Request:
GetNotifiersRequest - Response:
GetNotifiersResponse
- Request:
-
HealthCheck - Verify service health
- Request:
HealthCheckRequest - Response:
HealthCheckResponse
- Request:
Notification Types Supported
NOTIFICATION_TYPE_EMAIL- Email notificationsNOTIFICATION_TYPE_SLACK- Slack messagesNOTIFICATION_TYPE_NTFY- Ntfy.sh push notificationsNOTIFICATION_TYPE_STDOUT- Console output (development only)
Request Example Structure
message SendNotificationRequest {
NotificationType type = 1; // Required: email, slack, ntfy, stdout
string subject = 2; // Required: notification subject/title
string body = 3; // Required: notification body/content
repeated string recipients = 4; // Required: email addresses, slack channels, etc.
Priority priority = 5; // Optional: normal, high, critical
string account = 6; // Optional: specific notifier account to use
map<string, string> metadata = 7; // Optional: additional metadata
}
Implementation Goals
Please implement a client that:
- ✅ Uses a single long-lived gRPC connection
- ✅ Sends API key in metadata with every request
- ✅ Implements exponential backoff retry for rate limits
- ✅ Loads credentials from environment variables
- ✅ Uses context with timeout for all requests
- ✅ Implements keepalive to prevent connection timeouts
- ✅ Includes proper error handling for all error codes
- ✅ Logs important events without exposing credentials
- ✅ Provides a health check mechanism
- ✅ Includes graceful shutdown (connection cleanup)
- ✅ Is production-ready with proper error handling and logging
- ✅ Includes basic unit tests
Example Usage Pattern
The client should be usable like this:
// Initialize once at startup
client, err := notifier.NewClient(
os.Getenv("NOTIFIER_ADDRESS"),
os.Getenv("NOTIFIER_API_KEY"),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Use throughout application lifetime
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
resp, err := client.SendNotification(ctx, ¬ifier.SendRequest{
Type: notifier.TypeEmail,
Subject: "Important Alert",
Body: "This is a critical notification",
Recipients: []string{"admin@example.com"},
Priority: notifier.PriorityHigh,
})
if err != nil {
log.Printf("Failed to send notification: %v", err)
// Application continues - notification failure is not fatal
return
}
log.Printf("Notification sent successfully: %s", resp.NotificationID)
Additional Context
- This is a microservices architecture running in Kubernetes
- The notifier service handles routing to multiple notification backends (SMTP, Slack, Ntfy)
- The client may need to send notifications from multiple goroutines concurrently
- High reliability is important, but notification failures should not crash the application
- The API key has a rate limit of 100 requests per minute (may vary per key)
Code Generation Note
If you need the protobuf definitions, they can be generated from the service's proto files located at api/grpc/proto/notifier.proto in the notifier service repository.
Usage Instructions
Copy the prompt above and provide it to your AI assistant when building the client. The prompt includes:
- All authentication requirements and formats
- Connection management best practices
- Error handling strategies
- Security requirements
- Observability guidelines
- Complete API method listing
- Production-ready patterns
- Kubernetes deployment configuration
The AI assistant should generate:
- Complete, production-ready client code
- Proper connection pooling and keepalive
- Comprehensive error handling
- Secure credential management
- Health check implementation
- Unit tests
- Usage documentation
Review the generated code for:
- ✅ Single long-lived connection (not creating connections per request)
- ✅ API key sent in metadata with every RPC
- ✅ Keepalive configuration present
- ✅ Exponential backoff retry logic
- ✅ No hardcoded credentials
- ✅ Proper context timeouts
- ✅ Error handling for all gRPC error codes
- ✅ Graceful shutdown (Close() method)