2026-07-11 19:17:54 -07:00
|
|
|
|
# SQS-like Message Queue Service (kmsvc)
|
|
|
|
|
|
|
2026-07-19 09:29:17 -07:00
|
|
|
|
**Endpoint:** `https://kmsvc.riotpiao.com` (REST + gRPC-Gateway)
|
2026-07-11 19:17:54 -07:00
|
|
|
|
**Internal:** `kmsvc-management-service.sqs.svc.cluster.local:8080`
|
|
|
|
|
|
**Namespace:** `sqs`
|
|
|
|
|
|
|
|
|
|
|
|
## When to Use
|
|
|
|
|
|
|
|
|
|
|
|
- **Decouple services** — Producer doesn't wait for consumer
|
|
|
|
|
|
- **Async jobs** — Fire-and-forget processing (batch, email, webhooks)
|
|
|
|
|
|
- **FIFO ordering** — Guarantee message order within `MessageGroupId`
|
|
|
|
|
|
- **Durable delivery** — At-least-once (messages in Kafka, replicated 3×)
|
|
|
|
|
|
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
|
|
|
|
|
|
|
**1. Create a queue:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kubectl apply -f - <<EOF
|
|
|
|
|
|
apiVersion: kmsvc.io/v1
|
|
|
|
|
|
kind: Queue
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
name: orders
|
|
|
|
|
|
spec:
|
|
|
|
|
|
fifoQueue: false # standard queue
|
|
|
|
|
|
visibilityTimeoutSeconds: 30 # re-deliver if not acked
|
|
|
|
|
|
messageRetentionPeriodSeconds: 345600 # 4 days
|
|
|
|
|
|
partitionsPerShard: 6
|
|
|
|
|
|
maxReceiveCount: 5 # move to DLQ after 5 fails
|
|
|
|
|
|
EOF
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**2. Send message:**
|
|
|
|
|
|
```bash
|
2026-07-19 09:29:17 -07:00
|
|
|
|
curl -X POST https://kmsvc.riotpiao.com/v1/queues/orders/messages \
|
2026-07-11 19:17:54 -07:00
|
|
|
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
|
|
|
|
|
-d '{
|
|
|
|
|
|
"body": "{\"order_id\":123,\"total\":99.99}",
|
|
|
|
|
|
"attributes": {"source":"web","priority":"high"}
|
|
|
|
|
|
}'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**3. Receive message:**
|
|
|
|
|
|
```bash
|
2026-07-19 09:29:17 -07:00
|
|
|
|
curl "https://kmsvc.riotpiao.com/v1/queues/orders/messages?max_number_of_messages=10&wait_time_seconds=20" \
|
2026-07-11 19:17:54 -07:00
|
|
|
|
-H "Authorization: Bearer $JWT_TOKEN"
|
|
|
|
|
|
|
|
|
|
|
|
# Response:
|
|
|
|
|
|
# {
|
|
|
|
|
|
# "messages": [
|
|
|
|
|
|
# {
|
|
|
|
|
|
# "message_id": "abc-123",
|
|
|
|
|
|
# "receipt_handle": "...",
|
|
|
|
|
|
# "body": "{...}",
|
|
|
|
|
|
# "attributes": {...},
|
|
|
|
|
|
# "receive_count": 1
|
|
|
|
|
|
# }
|
|
|
|
|
|
# ]
|
|
|
|
|
|
# }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**4. Acknowledge (delete) message:**
|
|
|
|
|
|
```bash
|
2026-07-19 09:29:17 -07:00
|
|
|
|
curl -X DELETE "https://kmsvc.riotpiao.com/v1/queues/orders/messages/$receipt_handle" \
|
2026-07-11 19:17:54 -07:00
|
|
|
|
-H "Authorization: Bearer $JWT_TOKEN"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
|
|
|
|
|
|
| Key | Value |
|
|
|
|
|
|
|-----|-------|
|
|
|
|
|
|
| Kafka bootstrap | `kmsvc-kafka-bootstrap.sqs.svc.cluster.local:9092` |
|
|
|
|
|
|
| Redis | `kmsvc-redis-master.sqs.svc.cluster.local:6379` |
|
|
|
|
|
|
| Topic naming | `kmsvc.{queueName}.shard-{id}` |
|
|
|
|
|
|
| Replication | 3 replicas, min.insync.replicas=2 |
|
|
|
|
|
|
| Retention | 4 days (configurable per queue) |
|
|
|
|
|
|
|
|
|
|
|
|
## Common Patterns
|
|
|
|
|
|
|
|
|
|
|
|
**Batch processing:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
for i in {1..100}; do
|
2026-07-19 09:29:17 -07:00
|
|
|
|
curl -X POST https://kmsvc.riotpiao.com/v1/queues/jobs/messages \
|
2026-07-11 19:17:54 -07:00
|
|
|
|
-H "Authorization: Bearer $JWT_TOKEN" \
|
|
|
|
|
|
-d "{\"body\":\"task-$i\"}" &
|
|
|
|
|
|
done
|
|
|
|
|
|
wait
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**FIFO queue (order guaranteed per group):**
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
apiVersion: kmsvc.io/v1
|
|
|
|
|
|
kind: Queue
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
name: checkout-fifo
|
|
|
|
|
|
spec:
|
|
|
|
|
|
fifoQueue: true
|
|
|
|
|
|
visibilityTimeoutSeconds: 60
|
|
|
|
|
|
partitionsPerShard: 1
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Dead-letter queue (failed messages):**
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
apiVersion: kmsvc.io/v1
|
|
|
|
|
|
kind: Queue
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
name: orders-dlq
|
|
|
|
|
|
spec:
|
|
|
|
|
|
fifoQueue: false
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
apiVersion: kmsvc.io/v1
|
|
|
|
|
|
kind: Queue
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
name: orders
|
|
|
|
|
|
spec:
|
|
|
|
|
|
fifoQueue: false
|
|
|
|
|
|
maxReceiveCount: 3
|
|
|
|
|
|
deadLetterTargetQueue: orders-dlq # auto-route failures here
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Monitoring
|
|
|
|
|
|
|
|
|
|
|
|
**Grafana dashboard:** `svc-kmsvc` (automatically loaded)
|
|
|
|
|
|
|
|
|
|
|
|
**Key metrics:**
|
|
|
|
|
|
- `kmsvc_messages_sent_total` — total sent
|
|
|
|
|
|
- `kmsvc_messages_received_total` — total received
|
|
|
|
|
|
- `kmsvc_queue_depth` — pending messages per queue
|
|
|
|
|
|
- `kmsvc_message_visibility_timeout_seconds` — visibility window
|
|
|
|
|
|
|
|
|
|
|
|
**Redis in-flight tracking:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Connect to Redis
|
|
|
|
|
|
k port-forward -n sqs svc/redis 6379:6379 &
|
|
|
|
|
|
redis-cli
|
|
|
|
|
|
|
|
|
|
|
|
# Check pending messages
|
|
|
|
|
|
KEYS "kmsvc:pending:orders:*"
|
|
|
|
|
|
KEYS "kmsvc:inflight:*" | wc -l
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Authentication
|
|
|
|
|
|
|
|
|
|
|
|
**Requires JWT from Authentik:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Get token (device code flow)
|
2026-07-14 13:14:46 -07:00
|
|
|
|
core secrets login
|
2026-07-11 19:17:54 -07:00
|
|
|
|
|
|
|
|
|
|
# Use token
|
2026-07-14 13:14:46 -07:00
|
|
|
|
export JWT_TOKEN=$(core get cluster/kmsvc/jwt-token --key jwt-token)
|
2026-07-19 09:29:17 -07:00
|
|
|
|
curl -H "Authorization: Bearer $JWT_TOKEN" https://kmsvc.riotpiao.com/v1/queues
|
2026-07-11 19:17:54 -07:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Integration Example
|
|
|
|
|
|
|
|
|
|
|
|
**Story Crater backend consumer:**
|
|
|
|
|
|
```go
|
|
|
|
|
|
// Receive messages
|
|
|
|
|
|
messages, err := kmsvc.ReceiveMessage(ctx, &kmsvc.ReceiveMessageRequest{
|
|
|
|
|
|
QueueName: "story-crater",
|
|
|
|
|
|
MaxNumberOfMessages: 10,
|
|
|
|
|
|
WaitTimeSeconds: 20,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Process
|
|
|
|
|
|
for _, msg := range messages.Messages {
|
|
|
|
|
|
processMessage(msg.Body)
|
|
|
|
|
|
|
|
|
|
|
|
// Acknowledge on success
|
|
|
|
|
|
kmsvc.DeleteMessage(ctx, &kmsvc.DeleteMessageRequest{
|
|
|
|
|
|
QueueName: "story-crater",
|
|
|
|
|
|
ReceiptHandle: msg.ReceiptHandle,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Troubleshooting
|
|
|
|
|
|
|
|
|
|
|
|
**Queue stuck / high lag:**
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Check Kafka broker status
|
|
|
|
|
|
k exec -n sqs pod/kmsvc-kafka-0 -- kafka-broker-api-versions.sh --bootstrap-server localhost:9092
|
|
|
|
|
|
|
|
|
|
|
|
# Inspect queue topics
|
|
|
|
|
|
k exec -n sqs pod/kmsvc-kafka-0 -- kafka-topics.sh --bootstrap-server localhost:9092 --list | grep orders
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Messages not being consumed:**
|
|
|
|
|
|
- Check `maxReceiveCount` (may be routing to DLQ)
|
|
|
|
|
|
- Verify consumer has `ReceiveMessage` permission (JWT scope)
|
|
|
|
|
|
- Check Redis: `KEYS "kmsvc:fifo_lock:orders:*"` (may be blocked by visibility timeout)
|
|
|
|
|
|
|
|
|
|
|
|
See `/TROUBLESHOOTING.md` for full incident guide.
|