| name | go-arch-guard-batch |
| description | Use when scaffolding or maintaining a cron/scheduler batch job Go project with go-arch-guard. Handles flat-layout Batch preset setup and type pattern guidance. |
| user_invocable | true |
go-arch-guard โ Batch
cron, ์ค์ผ์ค๋ฌ(Airflow ๋ฑ), ์๋ ์คํ ๊ธฐ๋ฐ ๋ฐฐ์น ํ๋ก์ ํธ์ ์ํคํ
์ฒ ๊ฐ๋๋ ์ผ์ ์ ์ฉํ๋ค.
ํ๋ซ ๋ ์ด์์ โ 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/job 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.PresetBatch,
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/job/ ์๋์ ์ฒซ ๋ฒ์งธ ๋ฐฐ์น job์ ์ถ๊ฐํ์ธ์.
ํ์ผ๋ช
์ job_xxx.go, ํ์
์ XxxJob, Run ๋ฉ์๋ ํ์.
Layout Reference
cmd/batch/main.go
internal/
โโโ job/ # job_expire_files.go, job_cleanup_trash.go
โโโ service/ # ๋น์ฆ๋์ค ๋ก์ง
โโโ store/ # ์์์ฑ (DB, ์ธ๋ถ API)
โโโ model/ # ๋ฐ์ดํฐ ๊ตฌ์กฐ์ฒด
โโโ pkg/ # ๊ณต์ ์ธํ๋ผ
โโโ batchutil/ # ๋ฐฐ์น ๊ณตํต (progress reporter ๋ฑ)
๋ ์ด์ด ๋ฐฉํฅ
| from | ํ์ฉ๋ import |
|---|
job | service, model |
service | store, model |
store | model |
model | ์์ |
๋ชจ๋ ๋ ์ด์ด๋ pkg/๋ฅผ import ๊ฐ๋ฅ (model ์ ์ธ).
TypePattern
job/ ๋ด job_*.go ํ์ผ์ ๋์ํ๋ ํ์
๊ณผ ๋ฉ์๋๋ฅผ ๋ฐ๋์ ์ ์ํด์ผ ํ๋ค.
| ํ์ผ๋ช
| ํ์ ํ์
| ํ์ ๋ฉ์๋ |
|---|
job_expire_files.go | ExpireFilesJob | Run |
job_cleanup_trash.go | CleanupTrashJob | Run |
job/ ๋ด prefix๊ฐ ์๋ ํ์ผ (์: job.go, params.go)์ ๊ฒ์ฌ ๋์ ์๋.
์์
package job
import "context"
type ExpireFilesJob struct {
service *service.FileService
}
func (j *ExpireFilesJob) Run(ctx context.Context) error {
cursor := ""
for {
files, next, err := j.service.FetchExpired(ctx, cursor, 100)
if err != nil {
return err
}
if len(files) == 0 {
break
}
for _, f := range files {
_ = j.service.Expire(ctx, f)
}
cursor = next
}
return nil
}
๊ณตํต ํ์
(์ ํ์ฌํญ)
job/job.go์ ๊ณตํต ์ธํฐํ์ด์ค๋ ํ์
์ ์ ์ํ ์ ์๋ค. ๊ฐ์ ๋ ์๋.
package job
type Params struct {
StartDate string
EndDate string
BatchSize int
DryRun bool
ResumeFrom string
}
type Result struct {
Total int
Processed int
Skipped int
Failed int
}
cmd/batch/main.go ํจํด
package main
import (
"context"
"flag"
"log"
"os"
)
func main() {
jobName := flag.String("job", "", "job name to run")
dryRun := flag.Bool("dry-run", false, "dry run mode")
flag.Parse()
cfg := config.Load()
registry := map[string]interface{ Run(context.Context) error }{
"expire_files": newExpireFilesJob(cfg),
"cleanup_trash": newCleanupTrashJob(cfg),
}
j, ok := registry[*jobName]
if !ok {
log.Fatalf("unknown job: %s", *jobName)
}
if err := j.Run(context.Background()); err != nil {
log.Fatalf("job failed: %v", err)
}
log.Println("done")
}
์คํ: ./batch --job expire_files --dry-run
Options
ctx := core.NewContext(pkgs, "", "", presets.Batch(), []string{"internal/legacy/..."})
core.Run(ctx, presets.RecommendedBatch(),
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.* (๋๋ฉ์ธ ๊ฒฉ๋ฆฌ) โ ํ๋ซ ๋ ์ด์์์๋ ๋๋ฉ์ธ ๊ฐ๋
์์.