@mytechtoday/augment-extensions 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/augment-extensions/coding-standards/c/CHANGELOG.md +55 -0
- package/augment-extensions/coding-standards/c/LICENSE +22 -0
- package/augment-extensions/coding-standards/c/README.md +167 -0
- package/augment-extensions/coding-standards/c/config/defaults.json +26 -0
- package/augment-extensions/coding-standards/c/config/examples/embedded.yaml +25 -0
- package/augment-extensions/coding-standards/c/config/examples/systems.json +31 -0
- package/augment-extensions/coding-standards/c/config/schema.json +244 -0
- package/augment-extensions/coding-standards/c/docs/API.md +613 -0
- package/augment-extensions/coding-standards/c/docs/CONFIGURATION.md +259 -0
- package/augment-extensions/coding-standards/c/docs/USER_GUIDE.md +567 -0
- package/augment-extensions/coding-standards/c/examples/drivers/Makefile +33 -0
- package/augment-extensions/coding-standards/c/examples/drivers/README.md +192 -0
- package/augment-extensions/coding-standards/c/examples/drivers/dma-example.c +224 -0
- package/augment-extensions/coding-standards/c/examples/drivers/example.dts +64 -0
- package/augment-extensions/coding-standards/c/examples/drivers/platform-driver.c +174 -0
- package/augment-extensions/coding-standards/c/examples/embedded/README.md +167 -0
- package/augment-extensions/coding-standards/c/examples/embedded/gpio-control.c +172 -0
- package/augment-extensions/coding-standards/c/examples/embedded/timer-isr.c +198 -0
- package/augment-extensions/coding-standards/c/examples/embedded/uart-communication.c +212 -0
- package/augment-extensions/coding-standards/c/examples/kernel/Makefile +82 -0
- package/augment-extensions/coding-standards/c/examples/kernel/README.md +168 -0
- package/augment-extensions/coding-standards/c/examples/kernel/char-device.c +198 -0
- package/augment-extensions/coding-standards/c/examples/kernel/proc-file.c +131 -0
- package/augment-extensions/coding-standards/c/examples/kernel/simple-module.c +111 -0
- package/augment-extensions/coding-standards/c/examples/legacy/Makefile +62 -0
- package/augment-extensions/coding-standards/c/examples/legacy/README.md +255 -0
- package/augment-extensions/coding-standards/c/examples/legacy/c89-to-c11-migration.c +268 -0
- package/augment-extensions/coding-standards/c/examples/legacy/compatibility-layer.c +239 -0
- package/augment-extensions/coding-standards/c/examples/networking/Makefile +35 -0
- package/augment-extensions/coding-standards/c/examples/networking/README.md +207 -0
- package/augment-extensions/coding-standards/c/examples/networking/protocol-parser.c +270 -0
- package/augment-extensions/coding-standards/c/examples/networking/tcp-server.c +197 -0
- package/augment-extensions/coding-standards/c/examples/networking/udp-multicast.c +220 -0
- package/augment-extensions/coding-standards/c/examples/realtime/Makefile +53 -0
- package/augment-extensions/coding-standards/c/examples/realtime/README.md +199 -0
- package/augment-extensions/coding-standards/c/examples/realtime/deadline-monitoring.c +260 -0
- package/augment-extensions/coding-standards/c/examples/realtime/priority-scheduling.c +258 -0
- package/augment-extensions/coding-standards/c/examples/systems/Makefile +34 -0
- package/augment-extensions/coding-standards/c/examples/systems/README.md +123 -0
- package/augment-extensions/coding-standards/c/examples/systems/ipc-pipes.c +181 -0
- package/augment-extensions/coding-standards/c/examples/systems/process-management.c +153 -0
- package/augment-extensions/coding-standards/c/examples/systems/signal-handling.c +162 -0
- package/augment-extensions/coding-standards/c/module.json +149 -0
- package/augment-extensions/coding-standards/c/rules/categories/drivers.md +635 -0
- package/augment-extensions/coding-standards/c/rules/categories/embedded.md +510 -0
- package/augment-extensions/coding-standards/c/rules/categories/kernel.md +653 -0
- package/augment-extensions/coding-standards/c/rules/categories/legacy.md +526 -0
- package/augment-extensions/coding-standards/c/rules/categories/networking.md +735 -0
- package/augment-extensions/coding-standards/c/rules/categories/realtime.md +631 -0
- package/augment-extensions/coding-standards/c/rules/categories/systems.md +586 -0
- package/augment-extensions/coding-standards/c/rules/universal/const-correctness.md +275 -0
- package/augment-extensions/coding-standards/c/rules/universal/documentation.md +251 -0
- package/augment-extensions/coding-standards/c/rules/universal/error-handling.md +250 -0
- package/augment-extensions/coding-standards/c/rules/universal/header-guards.md +254 -0
- package/augment-extensions/coding-standards/c/rules/universal/memory-safety.md +233 -0
- package/augment-extensions/coding-standards/c/rules/universal/naming.md +146 -0
- package/augment-extensions/coding-standards/c/src/conflict-detector.ts +461 -0
- package/augment-extensions/coding-standards/c/src/prompt-generator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-evaluator.ts +307 -0
- package/augment-extensions/coding-standards/c/src/rule-override.ts +427 -0
- package/augment-extensions/coding-standards/c/src/template-engine.ts +217 -0
- package/augment-extensions/coding-standards/c/templates/prompts/drivers.txt +191 -0
- package/augment-extensions/coding-standards/c/templates/prompts/embedded.txt +164 -0
- package/augment-extensions/coding-standards/c/templates/prompts/kernel.txt +175 -0
- package/augment-extensions/coding-standards/c/templates/prompts/legacy.txt +280 -0
- package/augment-extensions/coding-standards/c/templates/prompts/networking.txt +259 -0
- package/augment-extensions/coding-standards/c/templates/prompts/realtime.txt +219 -0
- package/augment-extensions/coding-standards/c/templates/prompts/systems.txt +147 -0
- package/augment-extensions/coding-standards/c/tests/integration/category-specific.test.ts +356 -0
- package/augment-extensions/coding-standards/c/tests/integration/end-to-end-workflow.test.ts +377 -0
- package/augment-extensions/coding-standards/c/tests/performance/benchmarks.test.ts +407 -0
- package/augment-extensions/coding-standards/c/tests/unit/config-manager.test.ts +345 -0
- package/augment-extensions/coding-standards/c/tests/unit/conflict-detector.test.ts +294 -0
- package/augment-extensions/coding-standards/c/tests/unit/prompt-generator.test.ts +174 -0
- package/augment-extensions/coding-standards/c/tests/unit/registry.test.ts +313 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-evaluator.test.ts +318 -0
- package/augment-extensions/coding-standards/c/tests/unit/rule-override.test.ts +326 -0
- package/augment-extensions/coding-standards/c/tests/unit/template-engine.test.ts +314 -0
- package/augment-extensions/coding-standards/go/CHARACTER-COUNT-REPORT.md +135 -0
- package/augment-extensions/coding-standards/go/PHASE1-COMPLETION.md +146 -0
- package/augment-extensions/coding-standards/go/PHASE4-COMPLETION.md +184 -0
- package/augment-extensions/coding-standards/go/README.md +200 -0
- package/augment-extensions/coding-standards/go/VALIDATION-CHECKLIST.md +154 -0
- package/augment-extensions/coding-standards/go/config/examples/example-cli.json +15 -0
- package/augment-extensions/coding-standards/go/config/examples/example-microservices.json +21 -0
- package/augment-extensions/coding-standards/go/config/examples/example-multi-category.yaml +24 -0
- package/augment-extensions/coding-standards/go/config/examples/example-web.json +15 -0
- package/augment-extensions/coding-standards/go/config/schema.json +110 -0
- package/augment-extensions/coding-standards/go/docs/CATEGORIES.md +221 -0
- package/augment-extensions/coding-standards/go/docs/CONFIGURATION.md +198 -0
- package/augment-extensions/coding-standards/go/docs/TROUBLESHOOTING.md +285 -0
- package/augment-extensions/coding-standards/go/examples/cli/cobra-app.go +287 -0
- package/augment-extensions/coding-standards/go/examples/cloud-native-app.go +217 -0
- package/augment-extensions/coding-standards/go/examples/devops-tool.go +250 -0
- package/augment-extensions/coding-standards/go/examples/distributed-system.go +247 -0
- package/augment-extensions/coding-standards/go/examples/microservices/grpc-service.go +253 -0
- package/augment-extensions/coding-standards/go/examples/rest-api.go +270 -0
- package/augment-extensions/coding-standards/go/examples/web/http-server.go +224 -0
- package/augment-extensions/coding-standards/go/module.json +139 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/api-versioning.md +149 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rate-limiting.md +209 -0
- package/augment-extensions/coding-standards/go/rules/categories/api-development/rest-api-design.md +183 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/cloud-config.md +193 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/health-checks.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/cloud-native/kubernetes.md +180 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/automation.md +179 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/ci-cd-integration.md +147 -0
- package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/infrastructure-as-code.md +231 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/caching.md +150 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/consensus.md +187 -0
- package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/event-sourcing.md +246 -0
- package/augment-extensions/coding-standards/go/rules/cli/command-parsing.md +264 -0
- package/augment-extensions/coding-standards/go/rules/cli/configuration.md +268 -0
- package/augment-extensions/coding-standards/go/rules/cli/cross-platform.md +324 -0
- package/augment-extensions/coding-standards/go/rules/microservices/distributed-tracing.md +253 -0
- package/augment-extensions/coding-standards/go/rules/microservices/grpc.md +257 -0
- package/augment-extensions/coding-standards/go/rules/microservices/metrics.md +278 -0
- package/augment-extensions/coding-standards/go/rules/microservices/service-discovery.md +249 -0
- package/augment-extensions/coding-standards/go/rules/universal/code-organization.md +221 -0
- package/augment-extensions/coding-standards/go/rules/universal/documentation.md +269 -0
- package/augment-extensions/coding-standards/go/rules/universal/performance.md +323 -0
- package/augment-extensions/coding-standards/go/rules/universal/testing.md +162 -0
- package/augment-extensions/coding-standards/go/rules/web/graceful-shutdown.md +249 -0
- package/augment-extensions/coding-standards/go/rules/web/http-handlers.md +164 -0
- package/augment-extensions/coding-standards/go/rules/web/middleware.md +234 -0
- package/augment-extensions/coding-standards/go/rules/web/routing.md +251 -0
- package/augment-extensions/coding-standards/go/templates/prompts/api.md +160 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cli.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/cloud-native.md +121 -0
- package/augment-extensions/coding-standards/go/templates/prompts/devops.md +146 -0
- package/augment-extensions/coding-standards/go/templates/prompts/distributed.md +133 -0
- package/augment-extensions/coding-standards/go/templates/prompts/microservices.md +225 -0
- package/augment-extensions/coding-standards/go/templates/prompts/web.md +181 -0
- package/augment-extensions/coding-standards/go/tests/integration/module-integration.test.ts +164 -0
- package/augment-extensions/coding-standards/go/tests/unit/category-selection.test.ts +147 -0
- package/augment-extensions/coding-standards/go/tests/unit/module-structure.test.ts +154 -0
- package/augment-extensions/coding-standards/go/tests/validate-character-count.ps1 +13 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.ps1 +148 -0
- package/augment-extensions/coding-standards/go/tests/validate-examples.sh +135 -0
- package/cli/dist/analysis/ast-parser.d.ts +47 -0
- package/cli/dist/analysis/ast-parser.d.ts.map +1 -0
- package/cli/dist/analysis/ast-parser.js +161 -0
- package/cli/dist/analysis/ast-parser.js.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts +27 -0
- package/cli/dist/analysis/complexity-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/complexity-analyzer.js +189 -0
- package/cli/dist/analysis/complexity-analyzer.js.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts +23 -0
- package/cli/dist/analysis/dependency-analyzer.d.ts.map +1 -0
- package/cli/dist/analysis/dependency-analyzer.js +237 -0
- package/cli/dist/analysis/dependency-analyzer.js.map +1 -0
- package/cli/dist/analysis/index.d.ts +9 -0
- package/cli/dist/analysis/index.d.ts.map +1 -0
- package/cli/dist/analysis/index.js +25 -0
- package/cli/dist/analysis/index.js.map +1 -0
- package/cli/dist/analysis/security-scanner.d.ts +11 -0
- package/cli/dist/analysis/security-scanner.d.ts.map +1 -0
- package/cli/dist/analysis/security-scanner.js +294 -0
- package/cli/dist/analysis/security-scanner.js.map +1 -0
- package/cli/dist/analysis/types.d.ts +151 -0
- package/cli/dist/analysis/types.d.ts.map +1 -0
- package/cli/dist/analysis/types.js +6 -0
- package/cli/dist/analysis/types.js.map +1 -0
- package/cli/dist/cli.js +24 -0
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/code-analysis.d.ts +11 -0
- package/cli/dist/commands/code-analysis.d.ts.map +1 -0
- package/cli/dist/commands/code-analysis.js +412 -0
- package/cli/dist/commands/code-analysis.js.map +1 -0
- package/modules.md +99 -3
- package/package.json +14 -2
- package/cli/dist/commands/agent.d.ts +0 -37
- package/cli/dist/commands/agent.d.ts.map +0 -1
- package/cli/dist/commands/agent.js +0 -222
- package/cli/dist/commands/agent.js.map +0 -1
- package/cli/dist/commands/beads.d.ts +0 -64
- package/cli/dist/commands/beads.d.ts.map +0 -1
- package/cli/dist/commands/beads.js +0 -377
- package/cli/dist/commands/beads.js.map +0 -1
- package/cli/dist/commands/change.d.ts +0 -54
- package/cli/dist/commands/change.d.ts.map +0 -1
- package/cli/dist/commands/change.js +0 -243
- package/cli/dist/commands/change.js.map +0 -1
- package/cli/dist/commands/clean.d.ts +0 -15
- package/cli/dist/commands/clean.d.ts.map +0 -1
- package/cli/dist/commands/clean.js +0 -63
- package/cli/dist/commands/clean.js.map +0 -1
- package/cli/dist/commands/clone.d.ts +0 -15
- package/cli/dist/commands/clone.d.ts.map +0 -1
- package/cli/dist/commands/clone.js +0 -49
- package/cli/dist/commands/clone.js.map +0 -1
- package/cli/dist/commands/config.d.ts +0 -33
- package/cli/dist/commands/config.d.ts.map +0 -1
- package/cli/dist/commands/config.js +0 -166
- package/cli/dist/commands/config.js.map +0 -1
- package/cli/dist/commands/context.d.ts +0 -38
- package/cli/dist/commands/context.d.ts.map +0 -1
- package/cli/dist/commands/context.js +0 -205
- package/cli/dist/commands/context.js.map +0 -1
- package/cli/dist/commands/create.d.ts +0 -18
- package/cli/dist/commands/create.d.ts.map +0 -1
- package/cli/dist/commands/create.js +0 -178
- package/cli/dist/commands/create.js.map +0 -1
- package/cli/dist/commands/diff.d.ts +0 -19
- package/cli/dist/commands/diff.d.ts.map +0 -1
- package/cli/dist/commands/diff.js +0 -104
- package/cli/dist/commands/diff.js.map +0 -1
- package/cli/dist/commands/doctor.d.ts +0 -14
- package/cli/dist/commands/doctor.d.ts.map +0 -1
- package/cli/dist/commands/doctor.js +0 -62
- package/cli/dist/commands/doctor.js.map +0 -1
- package/cli/dist/commands/export.d.ts +0 -28
- package/cli/dist/commands/export.d.ts.map +0 -1
- package/cli/dist/commands/export.js +0 -135
- package/cli/dist/commands/export.js.map +0 -1
- package/cli/dist/commands/import.d.ts +0 -23
- package/cli/dist/commands/import.d.ts.map +0 -1
- package/cli/dist/commands/import.js +0 -118
- package/cli/dist/commands/import.js.map +0 -1
- package/cli/dist/commands/prompt.d.ts +0 -45
- package/cli/dist/commands/prompt.d.ts.map +0 -1
- package/cli/dist/commands/prompt.js +0 -223
- package/cli/dist/commands/prompt.js.map +0 -1
- package/cli/dist/commands/spec.d.ts +0 -57
- package/cli/dist/commands/spec.d.ts.map +0 -1
- package/cli/dist/commands/spec.js +0 -279
- package/cli/dist/commands/spec.js.map +0 -1
- package/cli/dist/commands/stats.d.ts +0 -18
- package/cli/dist/commands/stats.d.ts.map +0 -1
- package/cli/dist/commands/stats.js +0 -85
- package/cli/dist/commands/stats.js.map +0 -1
- package/cli/dist/commands/task.d.ts +0 -65
- package/cli/dist/commands/task.d.ts.map +0 -1
- package/cli/dist/commands/task.js +0 -282
- package/cli/dist/commands/task.js.map +0 -1
- package/cli/dist/commands/template.d.ts +0 -17
- package/cli/dist/commands/template.d.ts.map +0 -1
- package/cli/dist/commands/template.js +0 -55
- package/cli/dist/commands/template.js.map +0 -1
- package/cli/dist/utils/agent-config.d.ts +0 -129
- package/cli/dist/utils/agent-config.d.ts.map +0 -1
- package/cli/dist/utils/agent-config.js +0 -297
- package/cli/dist/utils/agent-config.js.map +0 -1
- package/cli/dist/utils/beads-graph.d.ts +0 -17
- package/cli/dist/utils/beads-graph.d.ts.map +0 -1
- package/cli/dist/utils/beads-graph.js +0 -150
- package/cli/dist/utils/beads-graph.js.map +0 -1
- package/cli/dist/utils/beads-integration.d.ts +0 -112
- package/cli/dist/utils/beads-integration.d.ts.map +0 -1
- package/cli/dist/utils/beads-integration.js +0 -312
- package/cli/dist/utils/beads-integration.js.map +0 -1
- package/cli/dist/utils/beads-reporter.d.ts +0 -17
- package/cli/dist/utils/beads-reporter.d.ts.map +0 -1
- package/cli/dist/utils/beads-reporter.js +0 -160
- package/cli/dist/utils/beads-reporter.js.map +0 -1
- package/cli/dist/utils/cache-manager.d.ts +0 -55
- package/cli/dist/utils/cache-manager.d.ts.map +0 -1
- package/cli/dist/utils/cache-manager.js +0 -150
- package/cli/dist/utils/cache-manager.js.map +0 -1
- package/cli/dist/utils/change-manager.d.ts +0 -70
- package/cli/dist/utils/change-manager.d.ts.map +0 -1
- package/cli/dist/utils/change-manager.js +0 -412
- package/cli/dist/utils/change-manager.js.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.d.ts +0 -66
- package/cli/dist/utils/config-manager-enhanced.d.ts.map +0 -1
- package/cli/dist/utils/config-manager-enhanced.js +0 -77
- package/cli/dist/utils/config-manager-enhanced.js.map +0 -1
- package/cli/dist/utils/context-manager.d.ts +0 -96
- package/cli/dist/utils/context-manager.d.ts.map +0 -1
- package/cli/dist/utils/context-manager.js +0 -258
- package/cli/dist/utils/context-manager.js.map +0 -1
- package/cli/dist/utils/diff-engine.d.ts +0 -78
- package/cli/dist/utils/diff-engine.d.ts.map +0 -1
- package/cli/dist/utils/diff-engine.js +0 -233
- package/cli/dist/utils/diff-engine.js.map +0 -1
- package/cli/dist/utils/export-system.d.ts +0 -101
- package/cli/dist/utils/export-system.d.ts.map +0 -1
- package/cli/dist/utils/export-system.js +0 -289
- package/cli/dist/utils/export-system.js.map +0 -1
- package/cli/dist/utils/health-checker.d.ts +0 -66
- package/cli/dist/utils/health-checker.d.ts.map +0 -1
- package/cli/dist/utils/health-checker.js +0 -285
- package/cli/dist/utils/health-checker.js.map +0 -1
- package/cli/dist/utils/import-system.d.ts +0 -74
- package/cli/dist/utils/import-system.d.ts.map +0 -1
- package/cli/dist/utils/import-system.js +0 -317
- package/cli/dist/utils/import-system.js.map +0 -1
- package/cli/dist/utils/module-cloner.d.ts +0 -40
- package/cli/dist/utils/module-cloner.d.ts.map +0 -1
- package/cli/dist/utils/module-cloner.js +0 -136
- package/cli/dist/utils/module-cloner.js.map +0 -1
- package/cli/dist/utils/prompt-manager.d.ts +0 -90
- package/cli/dist/utils/prompt-manager.d.ts.map +0 -1
- package/cli/dist/utils/prompt-manager.js +0 -302
- package/cli/dist/utils/prompt-manager.js.map +0 -1
- package/cli/dist/utils/spec-manager.d.ts +0 -65
- package/cli/dist/utils/spec-manager.d.ts.map +0 -1
- package/cli/dist/utils/spec-manager.js +0 -329
- package/cli/dist/utils/spec-manager.js.map +0 -1
- package/cli/dist/utils/stats-collector.d.ts +0 -74
- package/cli/dist/utils/stats-collector.d.ts.map +0 -1
- package/cli/dist/utils/stats-collector.js +0 -164
- package/cli/dist/utils/stats-collector.js.map +0 -1
- package/cli/dist/utils/template-engine.d.ts +0 -47
- package/cli/dist/utils/template-engine.d.ts.map +0 -1
- package/cli/dist/utils/template-engine.js +0 -204
- package/cli/dist/utils/template-engine.js.map +0 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// Package main demonstrates a cloud-native Go application with Kubernetes integration,
|
|
2
|
+
// configuration management, health checks, and graceful shutdown.
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"context"
|
|
7
|
+
"database/sql"
|
|
8
|
+
"encoding/json"
|
|
9
|
+
"fmt"
|
|
10
|
+
"log"
|
|
11
|
+
"net/http"
|
|
12
|
+
"os"
|
|
13
|
+
"os/signal"
|
|
14
|
+
"syscall"
|
|
15
|
+
"time"
|
|
16
|
+
|
|
17
|
+
"github.com/kelseyhightower/envconfig"
|
|
18
|
+
_ "github.com/lib/pq"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
// Config holds application configuration loaded from environment variables
|
|
22
|
+
type Config struct {
|
|
23
|
+
Port int `envconfig:"PORT" default:"8080"`
|
|
24
|
+
DatabaseURL string `envconfig:"DATABASE_URL" required:"true"`
|
|
25
|
+
LogLevel string `envconfig:"LOG_LEVEL" default:"info"`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// HealthChecker manages health check functions
|
|
29
|
+
type HealthChecker struct {
|
|
30
|
+
checks map[string]func(context.Context) error
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// NewHealthChecker creates a new health checker
|
|
34
|
+
func NewHealthChecker() *HealthChecker {
|
|
35
|
+
return &HealthChecker{
|
|
36
|
+
checks: make(map[string]func(context.Context) error),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// AddCheck adds a named health check function
|
|
41
|
+
func (hc *HealthChecker) AddCheck(name string, check func(context.Context) error) {
|
|
42
|
+
hc.checks[name] = check
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check runs all health checks and returns results
|
|
46
|
+
func (hc *HealthChecker) Check(ctx context.Context) (map[string]string, error) {
|
|
47
|
+
results := make(map[string]string)
|
|
48
|
+
var hasError bool
|
|
49
|
+
|
|
50
|
+
for name, check := range hc.checks {
|
|
51
|
+
checkCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
|
52
|
+
defer cancel()
|
|
53
|
+
|
|
54
|
+
if err := check(checkCtx); err != nil {
|
|
55
|
+
results[name] = fmt.Sprintf("FAIL: %v", err)
|
|
56
|
+
hasError = true
|
|
57
|
+
} else {
|
|
58
|
+
results[name] = "OK"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if hasError {
|
|
63
|
+
return results, fmt.Errorf("health check failed")
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return results, nil
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// HealthResponse represents the health check response
|
|
70
|
+
type HealthResponse struct {
|
|
71
|
+
Status string `json:"status"`
|
|
72
|
+
Timestamp time.Time `json:"timestamp"`
|
|
73
|
+
Components map[string]string `json:"components,omitempty"`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Application holds the application state
|
|
77
|
+
type Application struct {
|
|
78
|
+
config *Config
|
|
79
|
+
db *sql.DB
|
|
80
|
+
server *http.Server
|
|
81
|
+
checker *HealthChecker
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// NewApplication creates a new application instance
|
|
85
|
+
func NewApplication(cfg *Config) (*Application, error) {
|
|
86
|
+
// Connect to database
|
|
87
|
+
db, err := sql.Open("postgres", cfg.DatabaseURL)
|
|
88
|
+
if err != nil {
|
|
89
|
+
return nil, fmt.Errorf("failed to connect to database: %w", err)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Configure connection pool
|
|
93
|
+
db.SetMaxOpenConns(25)
|
|
94
|
+
db.SetMaxIdleConns(5)
|
|
95
|
+
db.SetConnMaxLifetime(5 * time.Minute)
|
|
96
|
+
|
|
97
|
+
// Verify connection
|
|
98
|
+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
99
|
+
defer cancel()
|
|
100
|
+
if err := db.PingContext(ctx); err != nil {
|
|
101
|
+
return nil, fmt.Errorf("failed to ping database: %w", err)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
app := &Application{
|
|
105
|
+
config: cfg,
|
|
106
|
+
db: db,
|
|
107
|
+
checker: NewHealthChecker(),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add health checks
|
|
111
|
+
app.checker.AddCheck("database", func(ctx context.Context) error {
|
|
112
|
+
return db.PingContext(ctx)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
return app, nil
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// healthHandler handles liveness probe requests
|
|
119
|
+
func (app *Application) healthHandler(w http.ResponseWriter, r *http.Request) {
|
|
120
|
+
w.WriteHeader(http.StatusOK)
|
|
121
|
+
w.Write([]byte("OK"))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// readinessHandler handles readiness probe requests
|
|
125
|
+
func (app *Application) readinessHandler(w http.ResponseWriter, r *http.Request) {
|
|
126
|
+
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
|
|
127
|
+
defer cancel()
|
|
128
|
+
|
|
129
|
+
components, err := app.checker.Check(ctx)
|
|
130
|
+
|
|
131
|
+
response := HealthResponse{
|
|
132
|
+
Timestamp: time.Now(),
|
|
133
|
+
Components: components,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if err != nil {
|
|
137
|
+
response.Status = "unhealthy"
|
|
138
|
+
w.WriteHeader(http.StatusServiceUnavailable)
|
|
139
|
+
} else {
|
|
140
|
+
response.Status = "healthy"
|
|
141
|
+
w.WriteHeader(http.StatusOK)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
w.Header().Set("Content-Type", "application/json")
|
|
145
|
+
json.NewEncoder(w).Encode(response)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Start starts the HTTP server
|
|
149
|
+
func (app *Application) Start() error {
|
|
150
|
+
mux := http.NewServeMux()
|
|
151
|
+
mux.HandleFunc("/health", app.healthHandler)
|
|
152
|
+
mux.HandleFunc("/ready", app.readinessHandler)
|
|
153
|
+
|
|
154
|
+
app.server = &http.Server{
|
|
155
|
+
Addr: fmt.Sprintf(":%d", app.config.Port),
|
|
156
|
+
Handler: mux,
|
|
157
|
+
ReadTimeout: 15 * time.Second,
|
|
158
|
+
WriteTimeout: 15 * time.Second,
|
|
159
|
+
IdleTimeout: 60 * time.Second,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
log.Printf("Starting server on port %d", app.config.Port)
|
|
163
|
+
return app.server.ListenAndServe()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Shutdown gracefully shuts down the application
|
|
167
|
+
func (app *Application) Shutdown(ctx context.Context) error {
|
|
168
|
+
log.Println("Shutting down gracefully...")
|
|
169
|
+
|
|
170
|
+
// Shutdown HTTP server
|
|
171
|
+
if err := app.server.Shutdown(ctx); err != nil {
|
|
172
|
+
return fmt.Errorf("server shutdown failed: %w", err)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Close database connection
|
|
176
|
+
if err := app.db.Close(); err != nil {
|
|
177
|
+
return fmt.Errorf("database close failed: %w", err)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
log.Println("Shutdown complete")
|
|
181
|
+
return nil
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
func main() {
|
|
185
|
+
// Load configuration
|
|
186
|
+
var cfg Config
|
|
187
|
+
if err := envconfig.Process("", &cfg); err != nil {
|
|
188
|
+
log.Fatalf("Failed to load config: %v", err)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Create application
|
|
192
|
+
app, err := NewApplication(&cfg)
|
|
193
|
+
if err != nil {
|
|
194
|
+
log.Fatalf("Failed to create application: %v", err)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Start server in goroutine
|
|
198
|
+
go func() {
|
|
199
|
+
if err := app.Start(); err != nil && err != http.ErrServerClosed {
|
|
200
|
+
log.Fatalf("Server failed: %v", err)
|
|
201
|
+
}
|
|
202
|
+
}()
|
|
203
|
+
|
|
204
|
+
// Wait for interrupt signal
|
|
205
|
+
quit := make(chan os.Signal, 1)
|
|
206
|
+
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
207
|
+
<-quit
|
|
208
|
+
|
|
209
|
+
// Graceful shutdown with timeout
|
|
210
|
+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
211
|
+
defer cancel()
|
|
212
|
+
|
|
213
|
+
if err := app.Shutdown(ctx); err != nil {
|
|
214
|
+
log.Fatalf("Shutdown failed: %v", err)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// Package main demonstrates a DevOps automation tool in Go with CLI,
|
|
2
|
+
// deployment automation, and infrastructure management capabilities.
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"context"
|
|
7
|
+
"fmt"
|
|
8
|
+
"log"
|
|
9
|
+
"os"
|
|
10
|
+
"time"
|
|
11
|
+
|
|
12
|
+
"github.com/spf13/cobra"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// DeploymentConfig holds deployment configuration
|
|
16
|
+
type DeploymentConfig struct {
|
|
17
|
+
Name string
|
|
18
|
+
Environment string
|
|
19
|
+
Version string
|
|
20
|
+
Replicas int
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// DeploymentStep represents a single deployment step
|
|
24
|
+
type DeploymentStep struct {
|
|
25
|
+
Name string
|
|
26
|
+
Description string
|
|
27
|
+
Execute func(context.Context) error
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// DeploymentOptions holds deployment options
|
|
31
|
+
type DeploymentOptions struct {
|
|
32
|
+
DryRun bool
|
|
33
|
+
Verbose bool
|
|
34
|
+
Timeout time.Duration
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Deployer handles deployment operations
|
|
38
|
+
type Deployer struct {
|
|
39
|
+
config *DeploymentConfig
|
|
40
|
+
options *DeploymentOptions
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// NewDeployer creates a new deployer
|
|
44
|
+
func NewDeployer(config *DeploymentConfig, options *DeploymentOptions) *Deployer {
|
|
45
|
+
return &Deployer{
|
|
46
|
+
config: config,
|
|
47
|
+
options: options,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Deploy executes the deployment
|
|
52
|
+
func (d *Deployer) Deploy(ctx context.Context) error {
|
|
53
|
+
steps := []DeploymentStep{
|
|
54
|
+
{
|
|
55
|
+
Name: "validate",
|
|
56
|
+
Description: "Validating configuration",
|
|
57
|
+
Execute: d.validateConfig,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
Name: "build",
|
|
61
|
+
Description: "Building application",
|
|
62
|
+
Execute: d.buildApplication,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
Name: "test",
|
|
66
|
+
Description: "Running tests",
|
|
67
|
+
Execute: d.runTests,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
Name: "deploy",
|
|
71
|
+
Description: "Deploying to environment",
|
|
72
|
+
Execute: d.deployToEnvironment,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
Name: "verify",
|
|
76
|
+
Description: "Verifying deployment",
|
|
77
|
+
Execute: d.verifyDeployment,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for i, step := range steps {
|
|
82
|
+
if d.options.Verbose {
|
|
83
|
+
log.Printf("[%d/%d] %s", i+1, len(steps), step.Description)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if d.options.DryRun {
|
|
87
|
+
log.Printf("[DRY RUN] Would execute: %s", step.Name)
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if err := step.Execute(ctx); err != nil {
|
|
92
|
+
return fmt.Errorf("step '%s' failed: %w", step.Name, err)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return nil
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func (d *Deployer) validateConfig(ctx context.Context) error {
|
|
100
|
+
if d.config.Name == "" {
|
|
101
|
+
return fmt.Errorf("deployment name is required")
|
|
102
|
+
}
|
|
103
|
+
if d.config.Environment == "" {
|
|
104
|
+
return fmt.Errorf("environment is required")
|
|
105
|
+
}
|
|
106
|
+
log.Println("Configuration validated")
|
|
107
|
+
return nil
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func (d *Deployer) buildApplication(ctx context.Context) error {
|
|
111
|
+
log.Printf("Building application version %s", d.config.Version)
|
|
112
|
+
time.Sleep(100 * time.Millisecond) // Simulate build
|
|
113
|
+
return nil
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func (d *Deployer) runTests(ctx context.Context) error {
|
|
117
|
+
log.Println("Running tests")
|
|
118
|
+
time.Sleep(100 * time.Millisecond) // Simulate tests
|
|
119
|
+
return nil
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func (d *Deployer) deployToEnvironment(ctx context.Context) error {
|
|
123
|
+
log.Printf("Deploying to %s environment", d.config.Environment)
|
|
124
|
+
time.Sleep(100 * time.Millisecond) // Simulate deployment
|
|
125
|
+
return nil
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func (d *Deployer) verifyDeployment(ctx context.Context) error {
|
|
129
|
+
log.Println("Verifying deployment health")
|
|
130
|
+
time.Sleep(100 * time.Millisecond) // Simulate verification
|
|
131
|
+
return nil
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Rollback performs deployment rollback
|
|
135
|
+
func (d *Deployer) Rollback(ctx context.Context, version string) error {
|
|
136
|
+
log.Printf("Rolling back to version %s", version)
|
|
137
|
+
|
|
138
|
+
if d.options.DryRun {
|
|
139
|
+
log.Println("[DRY RUN] Would rollback deployment")
|
|
140
|
+
return nil
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Simulate rollback
|
|
144
|
+
time.Sleep(100 * time.Millisecond)
|
|
145
|
+
log.Println("Rollback completed")
|
|
146
|
+
return nil
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var (
|
|
150
|
+
dryRun bool
|
|
151
|
+
verbose bool
|
|
152
|
+
version string
|
|
153
|
+
environment string
|
|
154
|
+
replicas int
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
var rootCmd = &cobra.Command{
|
|
158
|
+
Use: "devops-tool",
|
|
159
|
+
Short: "A DevOps automation tool",
|
|
160
|
+
Long: `A comprehensive DevOps automation tool for deployment and infrastructure management.`,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
var deployCmd = &cobra.Command{
|
|
164
|
+
Use: "deploy [name]",
|
|
165
|
+
Short: "Deploy application",
|
|
166
|
+
Args: cobra.ExactArgs(1),
|
|
167
|
+
RunE: func(cmd *cobra.Command, args []string) error {
|
|
168
|
+
name := args[0]
|
|
169
|
+
|
|
170
|
+
config := &DeploymentConfig{
|
|
171
|
+
Name: name,
|
|
172
|
+
Environment: environment,
|
|
173
|
+
Version: version,
|
|
174
|
+
Replicas: replicas,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
options := &DeploymentOptions{
|
|
178
|
+
DryRun: dryRun,
|
|
179
|
+
Verbose: verbose,
|
|
180
|
+
Timeout: 5 * time.Minute,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
deployer := NewDeployer(config, options)
|
|
184
|
+
|
|
185
|
+
ctx, cancel := context.WithTimeout(context.Background(), options.Timeout)
|
|
186
|
+
defer cancel()
|
|
187
|
+
|
|
188
|
+
if err := deployer.Deploy(ctx); err != nil {
|
|
189
|
+
return err
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
log.Printf("Deployment '%s' completed successfully", name)
|
|
193
|
+
return nil
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
var rollbackCmd = &cobra.Command{
|
|
198
|
+
Use: "rollback [name] [version]",
|
|
199
|
+
Short: "Rollback deployment",
|
|
200
|
+
Args: cobra.ExactArgs(2),
|
|
201
|
+
RunE: func(cmd *cobra.Command, args []string) error {
|
|
202
|
+
name := args[0]
|
|
203
|
+
targetVersion := args[1]
|
|
204
|
+
|
|
205
|
+
config := &DeploymentConfig{
|
|
206
|
+
Name: name,
|
|
207
|
+
Environment: environment,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
options := &DeploymentOptions{
|
|
211
|
+
DryRun: dryRun,
|
|
212
|
+
Verbose: verbose,
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
deployer := NewDeployer(config, options)
|
|
216
|
+
|
|
217
|
+
ctx := context.Background()
|
|
218
|
+
if err := deployer.Rollback(ctx, targetVersion); err != nil {
|
|
219
|
+
return err
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
log.Printf("Rollback to version %s completed", targetVersion)
|
|
223
|
+
return nil
|
|
224
|
+
},
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
func init() {
|
|
228
|
+
// Deploy command flags
|
|
229
|
+
deployCmd.Flags().StringVarP(&version, "version", "v", "latest", "Version to deploy")
|
|
230
|
+
deployCmd.Flags().StringVarP(&environment, "environment", "e", "production", "Target environment")
|
|
231
|
+
deployCmd.Flags().IntVarP(&replicas, "replicas", "r", 3, "Number of replicas")
|
|
232
|
+
deployCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Perform dry run")
|
|
233
|
+
deployCmd.Flags().BoolVar(&verbose, "verbose", false, "Verbose output")
|
|
234
|
+
|
|
235
|
+
// Rollback command flags
|
|
236
|
+
rollbackCmd.Flags().StringVarP(&environment, "environment", "e", "production", "Target environment")
|
|
237
|
+
rollbackCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Perform dry run")
|
|
238
|
+
rollbackCmd.Flags().BoolVar(&verbose, "verbose", false, "Verbose output")
|
|
239
|
+
|
|
240
|
+
rootCmd.AddCommand(deployCmd)
|
|
241
|
+
rootCmd.AddCommand(rollbackCmd)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
func main() {
|
|
245
|
+
if err := rootCmd.Execute(); err != nil {
|
|
246
|
+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
247
|
+
os.Exit(1)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Package main demonstrates a distributed system in Go with consensus,
|
|
2
|
+
// event sourcing, and distributed caching patterns.
|
|
3
|
+
package main
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"context"
|
|
7
|
+
"encoding/json"
|
|
8
|
+
"fmt"
|
|
9
|
+
"log"
|
|
10
|
+
"time"
|
|
11
|
+
|
|
12
|
+
"github.com/go-redis/redis/v8"
|
|
13
|
+
"github.com/google/uuid"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
// Event represents an immutable event in the system
|
|
17
|
+
type Event struct {
|
|
18
|
+
ID string `json:"id"`
|
|
19
|
+
AggregateID string `json:"aggregate_id"`
|
|
20
|
+
Type string `json:"type"`
|
|
21
|
+
Data json.RawMessage `json:"data"`
|
|
22
|
+
Metadata map[string]string `json:"metadata"`
|
|
23
|
+
Timestamp time.Time `json:"timestamp"`
|
|
24
|
+
Version int `json:"version"`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// EventStore interface for event persistence
|
|
28
|
+
type EventStore interface {
|
|
29
|
+
Save(ctx context.Context, events []Event) error
|
|
30
|
+
Load(ctx context.Context, aggregateID string) ([]Event, error)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// CacheManager handles distributed caching operations
|
|
34
|
+
type CacheManager struct {
|
|
35
|
+
client *redis.Client
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// NewCacheManager creates a new cache manager
|
|
39
|
+
func NewCacheManager(addr string) *CacheManager {
|
|
40
|
+
client := redis.NewClient(&redis.Options{
|
|
41
|
+
Addr: addr,
|
|
42
|
+
Password: "",
|
|
43
|
+
DB: 0,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return &CacheManager{client: client}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get retrieves a value from cache
|
|
50
|
+
func (cm *CacheManager) Get(ctx context.Context, key string) (string, error) {
|
|
51
|
+
return cm.client.Get(ctx, key).Result()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Set stores a value in cache with TTL
|
|
55
|
+
func (cm *CacheManager) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
|
|
56
|
+
return cm.client.Set(ctx, key, value, ttl).Err()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Delete removes a value from cache
|
|
60
|
+
func (cm *CacheManager) Delete(ctx context.Context, key string) error {
|
|
61
|
+
return cm.client.Del(ctx, key).Err()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// GetMultiple retrieves multiple values using pipelining
|
|
65
|
+
func (cm *CacheManager) GetMultiple(ctx context.Context, keys []string) (map[string]string, error) {
|
|
66
|
+
pipe := cm.client.Pipeline()
|
|
67
|
+
|
|
68
|
+
cmds := make(map[string]*redis.StringCmd)
|
|
69
|
+
for _, key := range keys {
|
|
70
|
+
cmds[key] = pipe.Get(ctx, key)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if _, err := pipe.Exec(ctx); err != nil && err != redis.Nil {
|
|
74
|
+
return nil, err
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
results := make(map[string]string)
|
|
78
|
+
for key, cmd := range cmds {
|
|
79
|
+
val, err := cmd.Result()
|
|
80
|
+
if err == redis.Nil {
|
|
81
|
+
continue
|
|
82
|
+
}
|
|
83
|
+
if err != nil {
|
|
84
|
+
return nil, err
|
|
85
|
+
}
|
|
86
|
+
results[key] = val
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return results, nil
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// User aggregate root
|
|
93
|
+
type User struct {
|
|
94
|
+
ID string
|
|
95
|
+
Email string
|
|
96
|
+
Name string
|
|
97
|
+
Version int
|
|
98
|
+
changes []Event
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// NewUser creates a new user
|
|
102
|
+
func NewUser(id, email, name string) *User {
|
|
103
|
+
return &User{
|
|
104
|
+
ID: id,
|
|
105
|
+
Email: email,
|
|
106
|
+
Name: name,
|
|
107
|
+
Version: 0,
|
|
108
|
+
changes: []Event{},
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ApplyEvent applies an event to the user aggregate
|
|
113
|
+
func (u *User) ApplyEvent(event Event) error {
|
|
114
|
+
switch event.Type {
|
|
115
|
+
case "UserCreated":
|
|
116
|
+
var data struct {
|
|
117
|
+
Email string `json:"email"`
|
|
118
|
+
Name string `json:"name"`
|
|
119
|
+
}
|
|
120
|
+
if err := json.Unmarshal(event.Data, &data); err != nil {
|
|
121
|
+
return err
|
|
122
|
+
}
|
|
123
|
+
u.Email = data.Email
|
|
124
|
+
u.Name = data.Name
|
|
125
|
+
|
|
126
|
+
case "UserEmailChanged":
|
|
127
|
+
var data struct {
|
|
128
|
+
NewEmail string `json:"new_email"`
|
|
129
|
+
}
|
|
130
|
+
if err := json.Unmarshal(event.Data, &data); err != nil {
|
|
131
|
+
return err
|
|
132
|
+
}
|
|
133
|
+
u.Email = data.NewEmail
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
u.Version = event.Version
|
|
137
|
+
return nil
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ChangeEmail changes the user's email
|
|
141
|
+
func (u *User) ChangeEmail(newEmail string) error {
|
|
142
|
+
if newEmail == u.Email {
|
|
143
|
+
return fmt.Errorf("email unchanged")
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
data, err := json.Marshal(map[string]string{
|
|
147
|
+
"old_email": u.Email,
|
|
148
|
+
"new_email": newEmail,
|
|
149
|
+
})
|
|
150
|
+
if err != nil {
|
|
151
|
+
return err
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
event := Event{
|
|
155
|
+
ID: uuid.New().String(),
|
|
156
|
+
AggregateID: u.ID,
|
|
157
|
+
Type: "UserEmailChanged",
|
|
158
|
+
Data: data,
|
|
159
|
+
Timestamp: time.Now(),
|
|
160
|
+
Version: u.Version + 1,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
u.changes = append(u.changes, event)
|
|
164
|
+
return u.ApplyEvent(event)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// GetUncommittedChanges returns uncommitted events
|
|
168
|
+
func (u *User) GetUncommittedChanges() []Event {
|
|
169
|
+
return u.changes
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// MarkChangesAsCommitted clears uncommitted changes
|
|
173
|
+
func (u *User) MarkChangesAsCommitted() {
|
|
174
|
+
u.changes = nil
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// DistributedService demonstrates distributed system patterns
|
|
178
|
+
type DistributedService struct {
|
|
179
|
+
cache *CacheManager
|
|
180
|
+
eventStore EventStore
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// NewDistributedService creates a new distributed service
|
|
184
|
+
func NewDistributedService(cache *CacheManager, eventStore EventStore) *DistributedService {
|
|
185
|
+
return &DistributedService{
|
|
186
|
+
cache: cache,
|
|
187
|
+
eventStore: eventStore,
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// GetUserWithCache retrieves user with cache-aside pattern
|
|
192
|
+
func (ds *DistributedService) GetUserWithCache(ctx context.Context, userID string) (*User, error) {
|
|
193
|
+
// Try cache first
|
|
194
|
+
cacheKey := fmt.Sprintf("user:%s", userID)
|
|
195
|
+
cached, err := ds.cache.Get(ctx, cacheKey)
|
|
196
|
+
if err == nil {
|
|
197
|
+
var user User
|
|
198
|
+
if err := json.Unmarshal([]byte(cached), &user); err == nil {
|
|
199
|
+
log.Printf("Cache hit for user %s", userID)
|
|
200
|
+
return &user, nil
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Cache miss - load from event store
|
|
205
|
+
log.Printf("Cache miss for user %s, loading from event store", userID)
|
|
206
|
+
events, err := ds.eventStore.Load(ctx, userID)
|
|
207
|
+
if err != nil {
|
|
208
|
+
return nil, err
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
user := &User{ID: userID}
|
|
212
|
+
for _, event := range events {
|
|
213
|
+
if err := user.ApplyEvent(event); err != nil {
|
|
214
|
+
return nil, err
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Store in cache
|
|
219
|
+
data, _ := json.Marshal(user)
|
|
220
|
+
ds.cache.Set(ctx, cacheKey, data, 1*time.Hour)
|
|
221
|
+
|
|
222
|
+
return user, nil
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
func main() {
|
|
226
|
+
ctx := context.Background()
|
|
227
|
+
|
|
228
|
+
// Initialize cache manager
|
|
229
|
+
cache := NewCacheManager("localhost:6379")
|
|
230
|
+
|
|
231
|
+
log.Println("Distributed system example started")
|
|
232
|
+
|
|
233
|
+
// Example: Cache operations
|
|
234
|
+
if err := cache.Set(ctx, "example:key", "example value", 5*time.Minute); err != nil {
|
|
235
|
+
log.Printf("Failed to set cache: %v", err)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
val, err := cache.Get(ctx, "example:key")
|
|
239
|
+
if err != nil {
|
|
240
|
+
log.Printf("Failed to get cache: %v", err)
|
|
241
|
+
} else {
|
|
242
|
+
log.Printf("Cache value: %s", val)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
log.Println("Distributed system example completed")
|
|
246
|
+
}
|
|
247
|
+
|