| name | go-arch-guard-consumer |
| description | Use when scaffolding or maintaining a Kafka/RabbitMQ/SQS consumer worker Go project with go-arch-guard. Handles flat-layout ConsumerWorker preset setup and type pattern guidance. |
| user_invocable | true |
go-arch-guard โ Consumer/Worker
Kafka, RabbitMQ, SQS ๋ฑ ๋ฉ์์ง ์ปจ์๋จธ ํ๋ก์ ํธ์ ์ํคํ
์ฒ ๊ฐ๋๋ ์ผ์ ์ ์ฉํ๋ค.
ํ๋ซ ๋ ์ด์์ โ internal/domain/ ์์ด ๋ ์ด์ด๊ฐ internal/ ๋ฐ๋ก ์๋์ ์์น.
Decision Flow
internal/ ์กด์ฌ ์ฌ๋ถ ํ์ธ
architecture_test.go ์กด์ฌ ์ฌ๋ถ ํ์ธ
์ ํ๋ก์ ํธ โ Quick Init ์คํ
๊ธฐ์กด ํ๋ก์ ํธ โ Layout Reference ์ฐธ์กฐํ์ฌ ์์
Quick Init
Step 1: ์ค์บํด๋ฉ
go get github.com/NamhaeSusan/go-arch-guard
mkdir -p internal/worker internal/service internal/store internal/model internal/pkg
Step 2: architecture_test.go ์์ฑ
ํ์ผ์ด ์ด๋ฏธ ์กด์ฌํ๋ฉด ๋ฎ์ด์ฐ์ง ์๊ณ ์ ์ ์๊ฒ ํ์ธํ๋ค.
ํจํค์ง๋ช
์ ์ ํจํ Go ํจํค์ง ์๋ณ์์ฌ์ผ ํ๋ค.
import "github.com/NamhaeSusan/go-arch-guard/scaffold"
src, err := scaffold.ArchitectureTest(
scaffold.PresetConsumerWorker,
scaffold.ArchitectureTestOptions{PackageName: "myapp_test"},
)
if err != nil {
return err
}
์์ฑ๋ ๊ฒฐ๊ณผ๋ฅผ architecture_test.go์ ์ ์ฅํ๋ค. ๋นํ์ค ํจํค์ง ๋ฃจํธ(packages/, src/)๋ฅผ ์ฐ๋ฉด ArchitectureTestOptions{..., InternalRoot: "packages"}๋ก ๊ฐ์ด ์ง์ ํ๋ค.
Step 3: ๊ฒ์ฆ
go test -run TestArchitecture -v
Step 4: ์๋ด
์ค์บํด๋ฉ ์๋ฃ. internal/worker/ ์๋์ ์ฒซ ๋ฒ์งธ worker๋ฅผ ์ถ๊ฐํ์ธ์.
ํ์ผ๋ช
์ worker_xxx.go, ํ์
์ XxxWorker, Process ๋ฉ์๋ ํ์.
Layout Reference
cmd/worker/main.go
internal/
โโโ worker/ # worker_order.go, worker_payment.go
โโโ service/ # ๋น์ฆ๋์ค ๋ก์ง
โโโ store/ # ์์์ฑ (DB, ์ธ๋ถ API)
โโโ model/ # ๋ฐ์ดํฐ ๊ตฌ์กฐ์ฒด
โโโ pkg/ # ๊ณต์ ์ธํ๋ผ
โโโ consumer/ # ๋ฉ์์ง ์์ ๊ณตํต ๋ก์ง
๋ ์ด์ด ๋ฐฉํฅ
| from | ํ์ฉ๋ import |
|---|
worker | service, model |
service | store, model |
store | model |
model | ์์ |
๋ชจ๋ ๋ ์ด์ด๋ pkg/๋ฅผ import ๊ฐ๋ฅ (model ์ ์ธ).
TypePattern
worker/ ๋ด worker_*.go ํ์ผ์ ๋์ํ๋ ํ์
๊ณผ ๋ฉ์๋๋ฅผ ๋ฐ๋์ ์ ์ํด์ผ ํ๋ค.
| ํ์ผ๋ช
| ํ์ ํ์
| ํ์ ๋ฉ์๋ |
|---|
worker_order.go | OrderWorker | Process |
worker_payment.go | PaymentWorker | Process |
worker/ ๋ด prefix๊ฐ ์๋ ํ์ผ (์: helper.go)์ ๊ฒ์ฌ ๋์ ์๋.
์์
package worker
import "context"
type OrderWorker struct {
service *service.OrderService
}
func (w *OrderWorker) Process(ctx context.Context) error {
return w.service.HandleOrderEvent(ctx, event)
}
cmd/worker/main.go ํจํด
package main
import (
"context"
"log"
"os/signal"
)
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
cfg := config.Load()
consumer := pkg.NewConsumer(cfg.BrokerAddrs, cfg.GroupID)
orderWorker := &worker.OrderWorker{...}
consumer.Subscribe("order-events", orderWorker.Process)
if err := consumer.Run(ctx); err != nil {
log.Fatal(err)
}
}
Options
ctx := core.NewContext(pkgs, "", "", presets.ConsumerWorker(), []string{"internal/legacy/..."})
core.Run(ctx, presets.RecommendedConsumerWorker(),
core.WithSeverityOverride("dependency.invalid-import-direction", core.Warning))
์ ์ฉ๋๋ ๊ท์น
| ์นดํ
๊ณ ๋ฆฌ | ๊ท์น |
|---|
| ๋ ์ด์ด ๋ฐฉํฅ | dependency.invalid-import-direction, dependency.inner-imports-pkg |
| ๊ตฌ์กฐ | structural.internal-top-level, structural.banned-package-name, structural.legacy-package, structural.middleware-placement |
| ๋ค์ด๋ฐ | naming.no-stutter, naming.no-impl-suffix, naming.snake-case-file, naming.no-layer-suffix, testpolicy.no-handmock |
| ํ์
ํจํด | naming.type-pattern-mismatch, naming.type-pattern-missing-method |
| ์ธํฐํ์ด์ค ํจํด | interfaces.exported-impl, interfaces.constructor-name, interfaces.constructor-returns-interface, interfaces.single-per-package |
| ์ปคํ๋ง | dependency.high-coupling |
๋ฏธ์ ์ฉ: dependency.* (๋๋ฉ์ธ ๊ฒฉ๋ฆฌ) โ ํ๋ซ ๋ ์ด์์์๋ ๋๋ฉ์ธ ๊ฐ๋
์์.