Skip to content

Commit ec85907

Browse files
Merge pull request #13 from majidgolshadi/doc
add docs
2 parents dad5ae1 + 05c7b8d commit ec85907

17 files changed

Lines changed: 49 additions & 15 deletions

File tree

cmd/server/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ func runServer() error {
6666

6767
logger.Info("telemetry initialized")
6868

69+
// Coordination DB is separate from the app DB so range reservation can be
70+
// scaled or failed over independently from URL data storage.
6971
coordinationDB, err := sql.NewDBFactory(newDBConfig(cfg.ServiceName, cfg.Coordination.DataStore)).CreateDB()
7072
if err != nil {
7173
return err
@@ -74,6 +76,8 @@ func runServer() error {
7476
coordinationStorage := mysqlRepo.NewCoordinator(coordinationDB, logger.WithField("component", "coordinator"))
7577
rangeMng := id.NewDataStoreRangeManager(cfg.Coordination.NodeID, cfg.Coordination.RangeSize, coordinationStorage)
7678

79+
// ID manager must claim a range before the server starts accepting traffic;
80+
// 3s is enough for a healthy DB but short enough to fail fast on startup.
7781
startupCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
7882
defer cancel()
7983

@@ -93,6 +97,7 @@ func runServer() error {
9397
customerSrv := customer.NewService(customerRepo, logger.WithField("component", "customer_service"))
9498

9599
ogFetchTimeout := cfg.OpenGraph.FetchTimeoutSec
100+
// A zero value means the field was omitted from config; fall back to a safe default.
96101
if ogFetchTimeout <= 0 {
97102
ogFetchTimeout = 10
98103
}

internal/domain/range.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package domain
22

3+
// Range is a pre-allocated block of integer IDs assigned exclusively to one node,
4+
// avoiding per-request DB coordination for ID generation.
35
type Range struct {
46
Start uint
57
End uint

internal/id/generator_integer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package id
22

33
import "sync"
44

5+
// IntegerIdGenerator is a simple monotonic counter.
6+
// Mutex is required because multiple goroutines may call NewID concurrently.
57
type IntegerIdGenerator struct {
68
mux sync.Mutex
79
id uint

internal/id/rangemanager_datastore.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ import (
1414
)
1515

1616
const (
17+
// reserveRangeMaxRetry: version mismatch means another node grabbed the range;
18+
// retry a few times before giving up to handle burst contention.
1719
reserveRangeMaxRetry = 3
1820

21+
// 200ms gives other nodes time to finish their transaction before we retry,
22+
// reducing thundering-herd when many nodes start simultaneously.
1923
reserveRangeWaitingTimeMillisecond = 200
2024
)
2125

@@ -78,7 +82,7 @@ func (c *datastoreRangeManager) getNextIDRange(ctx context.Context) (domain.Rang
7882

7983
// TODO: log the error as warning
8084

81-
// wait and then retry
85+
// version conflict: another node already claimed this range; backoff and retry
8286
time.Sleep(reserveRangeWaitingTimeMillisecond * time.Millisecond)
8387
}
8488

internal/id/rangemanager_inmemory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ func NewInMemoryRangeManager(startID uint) RangeManager {
1616
}
1717

1818
func (c *inMemory) getCurrentRange(ctx context.Context) (domain.Range, error) {
19+
// ^uint(0) is max uint — effectively unbounded, for single-node or test mode
20+
// where DB coordination is not needed.
1921
return domain.Range{
2022
Start: c.startID,
2123
End: ^uint(0),

internal/infrastructure/errors/error.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@ const (
2323
NotURLOwnerErr = errorStr("not url owner")
2424
)
2525

26+
// errorStr is a typed string constant so errors.Is() comparisons work without allocation
27+
// and cannot accidentally match unrelated string errors.
2628
type errorStr string
2729

2830
func (err errorStr) Error() string {
2931
return string(err)
3032
}
3133

34+
// Is unwraps both pkg/errors and fmt.Errorf chains so callers can use errors.Is()
35+
// regardless of how the error was wrapped.
3236
func (err errorStr) Is(target error) bool {
3337
targetError, ok := target.(errorStr)
3438
if ok {

internal/infrastructure/sql/factory.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func (f *DBFactory) CreateDB() (*sqlx.DB, error) {
4141
}
4242

4343
db.SetMaxOpenConns(f.config.MaxOpenConns)
44+
// ConnMaxLifetime prevents stale connections after MySQL's wait_timeout drops idle ones.
4445
db.SetConnMaxLifetime(f.config.ConnMaxLifetime)
4546

4647
return db, nil

internal/infrastructure/telemetry/telemetry.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ func initTracerProvider(ctx context.Context, cfg Config, res *resource.Resource)
116116
opts := []otlptracehttp.Option{
117117
otlptracehttp.WithEndpoint(cfg.OTLPEndpoint),
118118
}
119+
// TLS is skipped only in development; staging/production must use a secure collector.
119120
if cfg.Environment == "development" {
120121
opts = append(opts, otlptracehttp.WithInsecure())
121122
}
@@ -145,6 +146,7 @@ func initMeterProvider(ctx context.Context, cfg Config, res *resource.Resource)
145146
opts := []otlpmetrichttp.Option{
146147
otlpmetrichttp.WithEndpoint(cfg.OTLPEndpoint),
147148
}
149+
// TLS is skipped only in development; staging/production must use a secure collector.
148150
if cfg.Environment == "development" {
149151
opts = append(opts, otlpmetrichttp.WithInsecure())
150152
}

internal/opengraph/fetcher.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (f *Fetcher) FetchOgHTML(ctx context.Context, targetURL string) string {
5757
return ""
5858
}
5959

60-
// Limit reading to 1MB to avoid excessive memory usage
60+
// OG tags live in <head>, so 1MB is sufficient; reading the full body would waste memory.
6161
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
6262
if err != nil {
6363
return ""
@@ -139,7 +139,7 @@ func parseOgTags(htmlContent string) ogData {
139139
}
140140
}
141141

142-
// Stop parsing after </head> for efficiency
142+
// OG meta tags must appear in <head>; stop at <body> to avoid scanning the full document.
143143
if tagName == "body" {
144144
if og.Title == "" && fallbackTitle != "" {
145145
og.Title = fallbackTitle

internal/server/protocol/http/middleware/auth.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import (
1212
// ContextKey is the type used for context keys in this package.
1313
type ContextKey string
1414

15-
// TestCustomerContextKey is exported so tests in other packages can inject a customer into context.
15+
// TestCustomerContextKey is exported so integration tests can bypass DB lookup
16+
// by injecting a customer directly into the request context.
1617
const TestCustomerContextKey ContextKey = "customer"
1718

1819
const customerContextKey = TestCustomerContextKey

0 commit comments

Comments
 (0)