@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
package/augment-extensions/coding-standards/go/rules/categories/devops-tooling/ci-cd-integration.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# CI/CD Integration Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for integrating Go applications with CI/CD pipelines including GitHub Actions, GitLab CI, and Jenkins.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Provide Exit Codes for CI/CD
|
|
10
|
+
|
|
11
|
+
**Rule**: Return appropriate exit codes for CI/CD pipeline integration.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
func main() {
|
|
16
|
+
if err := run(); err != nil {
|
|
17
|
+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
|
18
|
+
|
|
19
|
+
// Return specific exit codes
|
|
20
|
+
switch err.(type) {
|
|
21
|
+
case *ValidationError:
|
|
22
|
+
os.Exit(2) // Configuration error
|
|
23
|
+
case *DeploymentError:
|
|
24
|
+
os.Exit(3) // Deployment error
|
|
25
|
+
default:
|
|
26
|
+
os.Exit(1) // General error
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
os.Exit(0) // Success
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Support Environment-Based Configuration
|
|
35
|
+
|
|
36
|
+
**Rule**: Configure behavior through environment variables for CI/CD compatibility.
|
|
37
|
+
|
|
38
|
+
**Good Example**:
|
|
39
|
+
```go
|
|
40
|
+
type CIConfig struct {
|
|
41
|
+
CI bool `envconfig:"CI" default:"false"`
|
|
42
|
+
Branch string `envconfig:"CI_COMMIT_BRANCH"`
|
|
43
|
+
CommitSHA string `envconfig:"CI_COMMIT_SHA"`
|
|
44
|
+
PipelineID string `envconfig:"CI_PIPELINE_ID"`
|
|
45
|
+
BuildNumber string `envconfig:"BUILD_NUMBER"`
|
|
46
|
+
ArtifactPath string `envconfig:"ARTIFACT_PATH" default:"./artifacts"`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
func LoadCIConfig() (*CIConfig, error) {
|
|
50
|
+
var cfg CIConfig
|
|
51
|
+
if err := envconfig.Process("", &cfg); err != nil {
|
|
52
|
+
return nil, err
|
|
53
|
+
}
|
|
54
|
+
return &cfg, nil
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Generate Machine-Readable Output
|
|
59
|
+
|
|
60
|
+
**Rule**: Support JSON output for CI/CD pipeline consumption.
|
|
61
|
+
|
|
62
|
+
**Good Example**:
|
|
63
|
+
```go
|
|
64
|
+
type TestResult struct {
|
|
65
|
+
Status string `json:"status"`
|
|
66
|
+
Duration time.Duration `json:"duration"`
|
|
67
|
+
Tests []TestCase `json:"tests"`
|
|
68
|
+
Coverage float64 `json:"coverage"`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func RunTests(outputFormat string) error {
|
|
72
|
+
result := executeTests()
|
|
73
|
+
|
|
74
|
+
switch outputFormat {
|
|
75
|
+
case "json":
|
|
76
|
+
return json.NewEncoder(os.Stdout).Encode(result)
|
|
77
|
+
case "junit":
|
|
78
|
+
return writeJUnitXML(result)
|
|
79
|
+
default:
|
|
80
|
+
return writeHumanReadable(result)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 4. Implement Artifact Publishing
|
|
86
|
+
|
|
87
|
+
**Rule**: Publish build artifacts with proper versioning and metadata.
|
|
88
|
+
|
|
89
|
+
**Good Example**:
|
|
90
|
+
```go
|
|
91
|
+
type Artifact struct {
|
|
92
|
+
Name string `json:"name"`
|
|
93
|
+
Version string `json:"version"`
|
|
94
|
+
Path string `json:"path"`
|
|
95
|
+
Checksum string `json:"checksum"`
|
|
96
|
+
Metadata map[string]string `json:"metadata"`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func PublishArtifact(ctx context.Context, artifact *Artifact) error {
|
|
100
|
+
// Calculate checksum
|
|
101
|
+
checksum, err := calculateSHA256(artifact.Path)
|
|
102
|
+
if err != nil {
|
|
103
|
+
return err
|
|
104
|
+
}
|
|
105
|
+
artifact.Checksum = checksum
|
|
106
|
+
|
|
107
|
+
// Add build metadata
|
|
108
|
+
artifact.Metadata = map[string]string{
|
|
109
|
+
"build_time": time.Now().Format(time.RFC3339),
|
|
110
|
+
"commit_sha": os.Getenv("CI_COMMIT_SHA"),
|
|
111
|
+
"pipeline_id": os.Getenv("CI_PIPELINE_ID"),
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Upload to artifact repository
|
|
115
|
+
return uploadArtifact(ctx, artifact)
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 5. Implement Health Checks for Deployment Verification
|
|
120
|
+
|
|
121
|
+
**Rule**: Provide health check endpoints for deployment verification in CI/CD.
|
|
122
|
+
|
|
123
|
+
**Good Example**:
|
|
124
|
+
```go
|
|
125
|
+
func WaitForDeployment(ctx context.Context, url string, timeout time.Duration) error {
|
|
126
|
+
deadline := time.Now().Add(timeout)
|
|
127
|
+
|
|
128
|
+
for time.Now().Before(deadline) {
|
|
129
|
+
resp, err := http.Get(url + "/health")
|
|
130
|
+
if err == nil && resp.StatusCode == http.StatusOK {
|
|
131
|
+
log.Println("Deployment healthy")
|
|
132
|
+
return nil
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
log.Printf("Waiting for deployment... (status: %v)", err)
|
|
136
|
+
time.Sleep(5 * time.Second)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return fmt.Errorf("deployment did not become healthy within %v", timeout)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## References
|
|
144
|
+
|
|
145
|
+
- [GitHub Actions](https://docs.github.com/en/actions)
|
|
146
|
+
- [GitLab CI/CD](https://docs.gitlab.com/ee/ci/)
|
|
147
|
+
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Infrastructure as Code Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for implementing Infrastructure as Code (IaC) tools in Go including Terraform providers, Pulumi programs, and custom IaC solutions.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Implement Declarative Configuration
|
|
10
|
+
|
|
11
|
+
**Rule**: Use declarative configuration for infrastructure definitions.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
type InfrastructureConfig struct {
|
|
16
|
+
Resources []Resource `yaml:"resources"`
|
|
17
|
+
Variables map[string]string `yaml:"variables"`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type Resource struct {
|
|
21
|
+
Type string `yaml:"type"`
|
|
22
|
+
Name string `yaml:"name"`
|
|
23
|
+
Properties map[string]interface{} `yaml:"properties"`
|
|
24
|
+
DependsOn []string `yaml:"depends_on,omitempty"`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func LoadConfig(path string) (*InfrastructureConfig, error) {
|
|
28
|
+
data, err := os.ReadFile(path)
|
|
29
|
+
if err != nil {
|
|
30
|
+
return nil, err
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var config InfrastructureConfig
|
|
34
|
+
if err := yaml.Unmarshal(data, &config); err != nil {
|
|
35
|
+
return nil, err
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return &config, nil
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. Implement State Management
|
|
43
|
+
|
|
44
|
+
**Rule**: Track infrastructure state to enable updates and drift detection.
|
|
45
|
+
|
|
46
|
+
**Good Example**:
|
|
47
|
+
```go
|
|
48
|
+
type StateManager struct {
|
|
49
|
+
backend StateBackend
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type State struct {
|
|
53
|
+
Version int `json:"version"`
|
|
54
|
+
Resources map[string]ResourceState `json:"resources"`
|
|
55
|
+
Outputs map[string]string `json:"outputs"`
|
|
56
|
+
UpdatedAt time.Time `json:"updated_at"`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func (sm *StateManager) SaveState(ctx context.Context, state *State) error {
|
|
60
|
+
state.UpdatedAt = time.Now()
|
|
61
|
+
state.Version++
|
|
62
|
+
|
|
63
|
+
data, err := json.Marshal(state)
|
|
64
|
+
if err != nil {
|
|
65
|
+
return err
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return sm.backend.Write(ctx, data)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func (sm *StateManager) LoadState(ctx context.Context) (*State, error) {
|
|
72
|
+
data, err := sm.backend.Read(ctx)
|
|
73
|
+
if err != nil {
|
|
74
|
+
return nil, err
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var state State
|
|
78
|
+
if err := json.Unmarshal(data, &state); err != nil {
|
|
79
|
+
return nil, err
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return &state, nil
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. Implement Dependency Resolution
|
|
87
|
+
|
|
88
|
+
**Rule**: Resolve resource dependencies and apply in correct order.
|
|
89
|
+
|
|
90
|
+
**Good Example**:
|
|
91
|
+
```go
|
|
92
|
+
func ResolveDependencies(resources []Resource) ([]Resource, error) {
|
|
93
|
+
graph := make(map[string][]string)
|
|
94
|
+
|
|
95
|
+
for _, res := range resources {
|
|
96
|
+
graph[res.Name] = res.DependsOn
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
sorted, err := topologicalSort(graph)
|
|
100
|
+
if err != nil {
|
|
101
|
+
return nil, err
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
result := make([]Resource, 0, len(resources))
|
|
105
|
+
for _, name := range sorted {
|
|
106
|
+
for _, res := range resources {
|
|
107
|
+
if res.Name == name {
|
|
108
|
+
result = append(result, res)
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result, nil
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 4. Implement Drift Detection
|
|
119
|
+
|
|
120
|
+
**Rule**: Detect configuration drift between desired and actual state.
|
|
121
|
+
|
|
122
|
+
**Good Example**:
|
|
123
|
+
```go
|
|
124
|
+
type DriftDetector struct {
|
|
125
|
+
provider ResourceProvider
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
type DriftResult struct {
|
|
129
|
+
Resource string
|
|
130
|
+
Expected interface{}
|
|
131
|
+
Actual interface{}
|
|
132
|
+
Drifted bool
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
func (dd *DriftDetector) DetectDrift(ctx context.Context, state *State) ([]DriftResult, error) {
|
|
136
|
+
var results []DriftResult
|
|
137
|
+
|
|
138
|
+
for name, expected := range state.Resources {
|
|
139
|
+
actual, err := dd.provider.GetResource(ctx, name)
|
|
140
|
+
if err != nil {
|
|
141
|
+
return nil, err
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
drifted := !reflect.DeepEqual(expected, actual)
|
|
145
|
+
|
|
146
|
+
results = append(results, DriftResult{
|
|
147
|
+
Resource: name,
|
|
148
|
+
Expected: expected,
|
|
149
|
+
Actual: actual,
|
|
150
|
+
Drifted: drifted,
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return results, nil
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 5. Support Plan and Apply Workflow
|
|
159
|
+
|
|
160
|
+
**Rule**: Implement plan phase to preview changes before applying.
|
|
161
|
+
|
|
162
|
+
**Good Example**:
|
|
163
|
+
```go
|
|
164
|
+
type Plan struct {
|
|
165
|
+
ToCreate []Resource
|
|
166
|
+
ToUpdate []Resource
|
|
167
|
+
ToDelete []Resource
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
func GeneratePlan(ctx context.Context, config *InfrastructureConfig, state *State) (*Plan, error) {
|
|
171
|
+
plan := &Plan{}
|
|
172
|
+
|
|
173
|
+
// Determine resources to create, update, or delete
|
|
174
|
+
for _, res := range config.Resources {
|
|
175
|
+
if existing, ok := state.Resources[res.Name]; ok {
|
|
176
|
+
if !resourceMatches(res, existing) {
|
|
177
|
+
plan.ToUpdate = append(plan.ToUpdate, res)
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
plan.ToCreate = append(plan.ToCreate, res)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for name := range state.Resources {
|
|
185
|
+
found := false
|
|
186
|
+
for _, res := range config.Resources {
|
|
187
|
+
if res.Name == name {
|
|
188
|
+
found = true
|
|
189
|
+
break
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if !found {
|
|
193
|
+
plan.ToDelete = append(plan.ToDelete, Resource{Name: name})
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return plan, nil
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
func ApplyPlan(ctx context.Context, plan *Plan, provider ResourceProvider) error {
|
|
201
|
+
// Delete resources
|
|
202
|
+
for _, res := range plan.ToDelete {
|
|
203
|
+
if err := provider.DeleteResource(ctx, res.Name); err != nil {
|
|
204
|
+
return err
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Create resources
|
|
209
|
+
for _, res := range plan.ToCreate {
|
|
210
|
+
if err := provider.CreateResource(ctx, &res); err != nil {
|
|
211
|
+
return err
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Update resources
|
|
216
|
+
for _, res := range plan.ToUpdate {
|
|
217
|
+
if err := provider.UpdateResource(ctx, &res); err != nil {
|
|
218
|
+
return err
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return nil
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## References
|
|
227
|
+
|
|
228
|
+
- [Terraform](https://www.terraform.io/)
|
|
229
|
+
- [Pulumi](https://www.pulumi.com/)
|
|
230
|
+
- [Infrastructure as Code Principles](https://www.hashicorp.com/resources/what-is-infrastructure-as-code)
|
|
231
|
+
|
package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/caching.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Distributed Caching Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for implementing distributed caching in Go applications using Redis, Memcached, and other caching solutions.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Cache-Aside Pattern
|
|
10
|
+
|
|
11
|
+
**Rule**: Implement cache-aside (lazy loading) pattern for most use cases.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
func GetUser(ctx context.Context, cache *redis.Client, db *sql.DB, userID string) (*User, error) {
|
|
16
|
+
// Try cache first
|
|
17
|
+
cacheKey := fmt.Sprintf("user:%s", userID)
|
|
18
|
+
cached, err := cache.Get(ctx, cacheKey).Result()
|
|
19
|
+
if err == nil {
|
|
20
|
+
var user User
|
|
21
|
+
if err := json.Unmarshal([]byte(cached), &user); err == nil {
|
|
22
|
+
return &user, nil
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Cache miss - load from database
|
|
27
|
+
user, err := loadUserFromDB(ctx, db, userID)
|
|
28
|
+
if err != nil {
|
|
29
|
+
return nil, err
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Store in cache
|
|
33
|
+
data, _ := json.Marshal(user)
|
|
34
|
+
cache.Set(ctx, cacheKey, data, 1*time.Hour)
|
|
35
|
+
|
|
36
|
+
return user, nil
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Set Appropriate TTLs
|
|
41
|
+
|
|
42
|
+
**Rule**: Always set TTL on cached items to prevent stale data.
|
|
43
|
+
|
|
44
|
+
**Good Example**:
|
|
45
|
+
```go
|
|
46
|
+
const (
|
|
47
|
+
UserCacheTTL = 1 * time.Hour
|
|
48
|
+
SessionCacheTTL = 15 * time.Minute
|
|
49
|
+
ConfigCacheTTL = 5 * time.Minute
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
func CacheUser(ctx context.Context, cache *redis.Client, user *User) error {
|
|
53
|
+
data, err := json.Marshal(user)
|
|
54
|
+
if err != nil {
|
|
55
|
+
return err
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
key := fmt.Sprintf("user:%s", user.ID)
|
|
59
|
+
return cache.Set(ctx, key, data, UserCacheTTL).Err()
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 3. Handle Cache Failures Gracefully
|
|
64
|
+
|
|
65
|
+
**Rule**: Application should continue working if cache is unavailable.
|
|
66
|
+
|
|
67
|
+
**Good Example**:
|
|
68
|
+
```go
|
|
69
|
+
func GetUserWithFallback(ctx context.Context, cache *redis.Client, db *sql.DB, userID string) (*User, error) {
|
|
70
|
+
// Try cache
|
|
71
|
+
if cache != nil {
|
|
72
|
+
if user, err := getUserFromCache(ctx, cache, userID); err == nil {
|
|
73
|
+
return user, nil
|
|
74
|
+
}
|
|
75
|
+
// Log cache error but continue
|
|
76
|
+
log.Printf("Cache error: %v, falling back to database", err)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Fallback to database
|
|
80
|
+
return loadUserFromDB(ctx, db, userID)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. Implement Cache Invalidation Strategy
|
|
85
|
+
|
|
86
|
+
**Rule**: Invalidate cache entries when data changes.
|
|
87
|
+
|
|
88
|
+
**Good Example**:
|
|
89
|
+
```go
|
|
90
|
+
func UpdateUser(ctx context.Context, cache *redis.Client, db *sql.DB, user *User) error {
|
|
91
|
+
// Update database
|
|
92
|
+
if err := updateUserInDB(ctx, db, user); err != nil {
|
|
93
|
+
return err
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Invalidate cache
|
|
97
|
+
cacheKey := fmt.Sprintf("user:%s", user.ID)
|
|
98
|
+
if err := cache.Del(ctx, cacheKey).Err(); err != nil {
|
|
99
|
+
log.Printf("Failed to invalidate cache: %v", err)
|
|
100
|
+
// Don't fail the operation if cache invalidation fails
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return nil
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 5. Use Pipelining for Batch Operations
|
|
108
|
+
|
|
109
|
+
**Rule**: Use pipelining to reduce network round trips for multiple cache operations.
|
|
110
|
+
|
|
111
|
+
**Good Example**:
|
|
112
|
+
```go
|
|
113
|
+
func GetMultipleUsers(ctx context.Context, cache *redis.Client, userIDs []string) (map[string]*User, error) {
|
|
114
|
+
pipe := cache.Pipeline()
|
|
115
|
+
|
|
116
|
+
cmds := make(map[string]*redis.StringCmd)
|
|
117
|
+
for _, userID := range userIDs {
|
|
118
|
+
key := fmt.Sprintf("user:%s", userID)
|
|
119
|
+
cmds[userID] = pipe.Get(ctx, key)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if _, err := pipe.Exec(ctx); err != nil && err != redis.Nil {
|
|
123
|
+
return nil, err
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
users := make(map[string]*User)
|
|
127
|
+
for userID, cmd := range cmds {
|
|
128
|
+
val, err := cmd.Result()
|
|
129
|
+
if err == redis.Nil {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
if err != nil {
|
|
133
|
+
return nil, err
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var user User
|
|
137
|
+
if err := json.Unmarshal([]byte(val), &user); err == nil {
|
|
138
|
+
users[userID] = &user
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return users, nil
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## References
|
|
147
|
+
|
|
148
|
+
- [Redis Best Practices](https://redis.io/docs/manual/patterns/)
|
|
149
|
+
- [Caching Strategies](https://docs.aws.amazon.com/AmazonElastiCache/latest/mem-ug/Strategies.html)
|
|
150
|
+
|
package/augment-extensions/coding-standards/go/rules/categories/distributed-systems/consensus.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Consensus and Distributed Coordination Rules
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Best practices for implementing consensus algorithms and distributed coordination in Go applications using Raft, etcd, and other consensus protocols.
|
|
6
|
+
|
|
7
|
+
## Rules
|
|
8
|
+
|
|
9
|
+
### 1. Use Proven Consensus Libraries
|
|
10
|
+
|
|
11
|
+
**Rule**: Use established consensus libraries like etcd/raft or HashiCorp Raft instead of implementing your own.
|
|
12
|
+
|
|
13
|
+
**Good Example**:
|
|
14
|
+
```go
|
|
15
|
+
import (
|
|
16
|
+
"github.com/hashicorp/raft"
|
|
17
|
+
raftboltdb "github.com/hashicorp/raft-boltdb"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
func NewRaftNode(nodeID, raftDir, raftBind string) (*raft.Raft, error) {
|
|
21
|
+
config := raft.DefaultConfig()
|
|
22
|
+
config.LocalID = raft.ServerID(nodeID)
|
|
23
|
+
|
|
24
|
+
store, err := raftboltdb.NewBoltStore(filepath.Join(raftDir, "raft.db"))
|
|
25
|
+
if err != nil {
|
|
26
|
+
return nil, fmt.Errorf("failed to create bolt store: %w", err)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
snapshots, err := raft.NewFileSnapshotStore(raftDir, 2, os.Stderr)
|
|
30
|
+
if err != nil {
|
|
31
|
+
return nil, fmt.Errorf("failed to create snapshot store: %w", err)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
transport, err := raft.NewTCPTransport(raftBind, nil, 3, 10*time.Second, os.Stderr)
|
|
35
|
+
if err != nil {
|
|
36
|
+
return nil, fmt.Errorf("failed to create transport: %w", err)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
r, err := raft.NewRaft(config, (*fsm)(s), store, store, snapshots, transport)
|
|
40
|
+
if err != nil {
|
|
41
|
+
return nil, fmt.Errorf("failed to create raft: %w", err)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return r, nil
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Implement Finite State Machine Correctly
|
|
49
|
+
|
|
50
|
+
**Rule**: Implement FSM with deterministic apply logic and proper snapshot/restore.
|
|
51
|
+
|
|
52
|
+
**Good Example**:
|
|
53
|
+
```go
|
|
54
|
+
type FSM struct {
|
|
55
|
+
mu sync.RWMutex
|
|
56
|
+
data map[string]string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func (f *FSM) Apply(log *raft.Log) interface{} {
|
|
60
|
+
f.mu.Lock()
|
|
61
|
+
defer f.mu.Unlock()
|
|
62
|
+
|
|
63
|
+
var cmd Command
|
|
64
|
+
if err := json.Unmarshal(log.Data, &cmd); err != nil {
|
|
65
|
+
return err
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
switch cmd.Op {
|
|
69
|
+
case "set":
|
|
70
|
+
f.data[cmd.Key] = cmd.Value
|
|
71
|
+
case "delete":
|
|
72
|
+
delete(f.data, cmd.Key)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return nil
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
func (f *FSM) Snapshot() (raft.FSMSnapshot, error) {
|
|
79
|
+
f.mu.RLock()
|
|
80
|
+
defer f.mu.RUnlock()
|
|
81
|
+
|
|
82
|
+
data := make(map[string]string)
|
|
83
|
+
for k, v := range f.data {
|
|
84
|
+
data[k] = v
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return &fsmSnapshot{data: data}, nil
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func (f *FSM) Restore(rc io.ReadCloser) error {
|
|
91
|
+
f.mu.Lock()
|
|
92
|
+
defer f.mu.Unlock()
|
|
93
|
+
|
|
94
|
+
decoder := json.NewDecoder(rc)
|
|
95
|
+
return decoder.Decode(&f.data)
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Handle Leader Election Properly
|
|
100
|
+
|
|
101
|
+
**Rule**: Always check if node is leader before accepting writes.
|
|
102
|
+
|
|
103
|
+
**Good Example**:
|
|
104
|
+
```go
|
|
105
|
+
func (s *Store) Set(key, value string) error {
|
|
106
|
+
if s.raft.State() != raft.Leader {
|
|
107
|
+
return fmt.Errorf("not leader")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
cmd := Command{
|
|
111
|
+
Op: "set",
|
|
112
|
+
Key: key,
|
|
113
|
+
Value: value,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
data, err := json.Marshal(cmd)
|
|
117
|
+
if err != nil {
|
|
118
|
+
return err
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
future := s.raft.Apply(data, 10*time.Second)
|
|
122
|
+
return future.Error()
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 4. Implement Read Consistency Levels
|
|
127
|
+
|
|
128
|
+
**Rule**: Provide different read consistency levels (strong, eventual).
|
|
129
|
+
|
|
130
|
+
**Good Example**:
|
|
131
|
+
```go
|
|
132
|
+
func (s *Store) Get(key string, consistent bool) (string, error) {
|
|
133
|
+
if consistent {
|
|
134
|
+
// Strong consistency: verify leadership
|
|
135
|
+
if err := s.raft.VerifyLeader().Error(); err != nil {
|
|
136
|
+
return "", err
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
s.mu.RLock()
|
|
141
|
+
defer s.mu.RUnlock()
|
|
142
|
+
|
|
143
|
+
value, ok := s.data[key]
|
|
144
|
+
if !ok {
|
|
145
|
+
return "", fmt.Errorf("key not found")
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return value, nil
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 5. Handle Network Partitions Gracefully
|
|
153
|
+
|
|
154
|
+
**Rule**: Implement proper timeout and retry logic for network partitions.
|
|
155
|
+
|
|
156
|
+
**Good Example**:
|
|
157
|
+
```go
|
|
158
|
+
func (s *Store) SetWithRetry(key, value string, maxRetries int) error {
|
|
159
|
+
var lastErr error
|
|
160
|
+
|
|
161
|
+
for i := 0; i < maxRetries; i++ {
|
|
162
|
+
err := s.Set(key, value)
|
|
163
|
+
if err == nil {
|
|
164
|
+
return nil
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
lastErr = err
|
|
168
|
+
|
|
169
|
+
if err.Error() == "not leader" {
|
|
170
|
+
// Wait for leader election
|
|
171
|
+
time.Sleep(time.Duration(i+1) * 100 * time.Millisecond)
|
|
172
|
+
continue
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return err
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return fmt.Errorf("failed after %d retries: %w", maxRetries, lastErr)
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## References
|
|
183
|
+
|
|
184
|
+
- [HashiCorp Raft](https://github.com/hashicorp/raft)
|
|
185
|
+
- [etcd Raft Library](https://github.com/etcd-io/etcd/tree/main/raft)
|
|
186
|
+
- [Raft Consensus Algorithm](https://raft.github.io/)
|
|
187
|
+
|