chore: initial import from sless/shared-sqs (v0.1.14)

- Standalone SQS-service repository
- Multi-tenant message queue service, AWS SQS compatible
- Based on GoAws, with mutable tenants, auth, WebUI, Redis persistence
- Ready for independent development and deployment
- See doc/ and README.md for architecture and usage
This commit is contained in:
Naeel
2026-04-10 16:47:27 +03:00
commit c3ba2dcae4
81 changed files with 14253 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
# BYOC — Bring Your Own Credentials
**Дата**: 2026-04-09
**Статус**: частично реализовано (backend), UI/API — TODO
---
## Суть
Возможность создать тенанта с **произвольными** Access Key и Secret Key вместо авто-генерируемых.
Нужно для:
- демо-стенда с фиксированными credentials (README всегда актуален)
- интеграционных тестов с предсказуемыми значениями
- миграции с другого SQS-совместимого сервиса (сохранение существующих ключей)
---
## Что уже сделано
### `app/tenant/tenant_store.go` — `CreateFixed`
```go
func (s *TenantStore) CreateFixed(
name string,
maxQueues int,
tenantID string,
accessKey string,
secretKey string,
) (*Tenant, error)
```
Создаёт тенанта с заранее известными credentials.
Проверяет уникальность и `tenantID`, и `accessKey` — конфликт возвращает ошибку.
### `app/cmd/seed.go` — демо-тенант
Использует `CreateFixed` при `SHARED_SQS_SEED_DEMO=true`:
```
tenantID = "t-demo-shared-sqs-ngcloud"
accessKey = "SSAK-demo-shared-sqs"
secretKey = "demo-secret-key-shared-sqs-ngcloud-2026"
```
---
## Что нужно сделать (TODO)
### Admin API — `POST /admin/tenants`
Добавить в `createTenantRequest` два опциональных поля:
```go
// app/admin/admin.go
type createTenantRequest struct {
Name string `json:"name"`
MaxQueues int `json:"max_queues"`
AccessKey string `json:"access_key,omitempty"` // TODO: BYOC
SecretKey string `json:"secret_key,omitempty"` // TODO: BYOC
}
```
Логика в `createTenant` handler:
```go
var t *tenant.Tenant
var err error
if req.AccessKey != "" || req.SecretKey != "" {
// BYOC: оба поля обязательны
if req.AccessKey == "" || req.SecretKey == "" {
jsonErr(w, http.StatusBadRequest, "both access_key and secret_key required when specifying custom credentials")
return
}
// Минимальная длина — защита от случайно слабых ключей
if len(req.AccessKey) < 8 || len(req.SecretKey) < 16 {
jsonErr(w, http.StatusBadRequest, "access_key min 8 chars, secret_key min 16 chars")
return
}
t, err = h.store.CreateFixed(req.Name, req.MaxQueues, generateTenantID(), req.AccessKey, req.SecretKey)
} else {
t, err = h.store.Create(req.Name, req.MaxQueues)
}
```
> `generateTenantID()` — уже есть в tenant_store.go, нужно экспортировать или вынести.
### UI — Web форма создания тенанта
- Добавить в модальное окно "Создать тенанта" два опциональных поля: Access Key, Secret Key
- Показывать только если нажата кнопка "задать свои credentials"
- Валидация на клиенте: оба поля заполнены, мин. длина
---
## Безопасность
- BYOC-credentials **не дают доступа к admin API** — admin защищён отдельным Bearer токеном
- Тенант видит **только свои очереди** — изоляция по AccessKey в auth middleware
- Слабые ключи отклоняются на уровне API (минимальная длина)
- Credentials передаются только по HTTPS
---
## Демо-credentials (открыты намеренно)
| | |
|---|---|
| **Access Key** | `SSAK-demo-shared-sqs` |
| **Secret Key** | `demo-secret-key-shared-sqs-ngcloud-2026` |
| **Tenant ID** | `t-demo-shared-sqs-ngcloud` |
| **Лимит очередей** | 10 |
Эти credentials жёстко прописаны в `app/cmd/seed.go`.
Тенант создаётся только если `SHARED_SQS_SEED_DEMO=true` (env var в deployment.yaml).
+79
View File
@@ -0,0 +1,79 @@
# SQS-service Progress
## Версага v0.1.x
### v0.1.14 (2026-04-10) ✅
- ✅ Фикс критического дедлока в `create_queue.go` (deadlock после первого CreateQueue)
- ✅ Фикс UI: `m.sent``m.sent_at` (даты сообщений всегда показывали dash)
- ✅ Redis write-through persistence запущен
- ✅ TLS Ingress: `qu.kube5s.ru``185.247.187.151`
- ✅ Нагрузочный тест Harbor: 4757 запросов, 99% успех, p95=332ms
- **Status: Production-ready для демо, готов к выводу за скобки в отдельный репо**
## Next Steps
- [ ] Migration guide: как обновить сервис на v0.1.14
- [ ] Load testing shared-sqs (текущая реализация имеет глобальный мьютекс)
- [ ] DLQ (Dead Letter Queue) поддержка
- [ ] Long Polling оптимизация
- [ ] Rate limiting per tenant
## Known Limitations
1. **Глобальный мьютекс** — SyncQueues.Lock() на весь сервис. Performance bottleneck.
2. **Нет DLQ** — failed messages теряются
3. **Long Polling naïve** — polling каждую 100ms вместо push-based
4. **Нет rate limiting** — один тенант может забить всех
5. **Single pod** — нет горизонтального масштабирования
6. **Нет метрик** — Prometheus экспортер отсутствует
## Architecture
```
SQS-service/
├── app/
│ ├── cmd/main.go — точка входа
│ ├── models/model.go — Queue, Message, Tenant структуры
│ ├── gosqs/*.go — реализация SQS API операций
│ ├── admin/admin.go — Admin API (Create/List/Get Tenant)
│ ├── tenant/tenant.go — Multi-tenant изоляция
│ ├── auth/auth.go — AWS Signature V4 верификация
│ ├── persistence/redis.go — Redis adapter для persistence
│ ├── router/router.go — HTTP маршруты
│ └── ui/index.html — Web Console
├── deployments/k8s/ — Kubernetes манифесты
├── tests/ — E2E тесты
└── doc/ — Документация
```
## Technology Stack
- **Language**: Go 1.22
- **HTTP Server**: Go std net/http
- **Auth**: AWS Signature V4
- **Storage**: Redis (write-through)
- **Container**: Docker
- **Orchestration**: Kubernetes
- **DNS**: Ingress с TLS
## Demo Credentials (read-only для тестирования)
```
Access Key: SSAK-demo-shared-sqs
Secret Key: demo-secret-key-shared-sqs-ngcloud-2026
Endpoint: https://qu.kube5s.ru
```
## Deployment
```bash
# Kubernetes
kubectl apply -k deployments/k8s/
# Docker (local)
docker run -p 9090:9090 naeel/shared-sqs:v0.1.14
```
---
*Last updated: 2026-04-10*
+90
View File
@@ -0,0 +1,90 @@
# Thinking Log — 2026-04-10
# Agent: GitHub Copilot (Claude Sonnet 4.6)
---
## Сессия 1
### Задача
1. Задокументировать итоги работы над shared-sqs (v0.1.11v0.1.14)
2. Закоммитить и запушить все изменения
3. Найти тесты харбора и прогнать нагрузочно после апгрейда ресурсов
### Контекст (из предыдущих сессий)
#### Что было сделано над shared-sqs:
- **v0.1.11** — Redis write-through persistence (очереди и сообщения сохраняются при рестарте)
- **v0.1.12** — промежуточный билд
- **v0.1.13** — КРИТИЧЕСКИЙ фикс дедлока в `create_queue.go`: `SyncQueues.Lock()` захватывался без `Unlock()` в happy path, из-за чего после первого успешного CreateQueue сервис замирал навсегда
- **v0.1.14** — фикс UI: JS читал поле `m.sent`, API отдавал `m.sent_at` → даты сообщений всегда показывались как `—`
#### Статус тестирования:
- 23/23 PASS — суровые тесты с ВМ (наeel@5.172.178.213)
- 6/6 PASS — quick_test.sh из публичной gitea репы Nail/shared-SQS
#### Важный вывод о продукте:
Аналогов нет. GitHub search `multi-tenant sqs compatible` → 0 результатов.
Ближайшее: ElasticMQ (single-tenant, local dev only) и GoAws (то же самое).
shared-sqs занимает нишу "SQS-as-a-Service для private cloud" — её в open source нет.
### Изменённые файлы в текущем коммите:
- `app/gosqs/create_queue.go` — фикс дедлока (Unlock перед return в happy path)
- `app/gosqs/delete_queue.go` — рефакторинг под новую модель с Redis
- `app/gosqs/purge_queue.go` — то же
- `app/gosqs/send_message.go` — то же
- `app/gosqs/set_queue_attributes.go` — то же
- `app/router/router.go` — маршруты
- `app/ui/index.html` — фикс `m.sent``m.sent_at`
- `deployments/k8s/deployment.yaml` — образ v0.1.14
- `deployments/k8s/ingress.yaml` — TLS endpoint qu.kube5s.ru
- `deployments/k8s/redis.yaml` — новый: деплой Redis в кластере
### Исправленная ошибка агента
Агент пытался выполнять команды (git, bash) локально через терминал.
**ПРАВИЛО**: `/home/naeel/remote_dev/sless` — это sshfs-mount.
Все файлы физически на ВМ `naeel@5.172.178.213:/home/naeel/terra/sless`.
Все команды — ТОЛЬКО через SSH на ВМ.
### План на сессию
1. ✅ Написать thinking log
2. Закоммитить изменения shared-sqs на ВМ
3. Найти `test_harbor_load.sh` в корне проекта, изучить
4. Прогнать нагрузочный тест харбора с ВМ, сравнить с предыдущими результатами
---
## Результаты нагрузочного теста Harbor (2026-04-10, после апгрейда ресурсов)
Команда: `cd /home/naeel/terra/sless && bash test_harbor_load.sh`
Параметры: 60 сек, 10 воркеров, таймаут 8 сек/запрос
```
Total requests : 4757
Success (2xx) : 4756 (99%)
Timeouts : 1 (0%)
Other errors : 0
Latency (ok) : min=0.023s median=0.044s p95=0.332s max=3.920s
--- By protocol ---
h1: ok=2347 fail=1 p95=0.342s
h2: ok=2409 fail=0 p95=0.314s
--- By URL ---
/api/v2.0/ping : ok=2660 timeout=1
/api/v2.0/projects: ok=1476 timeout=0
/v2/ : ok=620 timeout=0
```
### Сравнение с историческим состоянием
**До апгрейда** (из doc/log.md, 2026-03-08):
> Harbor нестабилен: `/v2/` периодически зависает на 10+ секунд или возвращает 504. Kaniko не мог завершить push образа.
**После апгрейда памяти и диска:**
- 1 таймаут из 4757 запросов (0%) — единичный инцидент на `/ping`
- Медиана 44ms — отличная latency
- p95 = 332ms — в норме
- max = 3.9s — единственный выброс (тот самый таймаут)
- H2 и H1 работают одинаково хорошо
**Вывод: харбор стабилен.** Апгрейд ресурсов полностью устранил проблему с зависаниями. Harbor пригоден для использования как registry для kaniko push.