Skip to content

Commit e7db943

Browse files
committed
Add loger, tally and renames and decouple the server from controllers
1 parent c4ceb4c commit e7db943

22 files changed

Lines changed: 435 additions & 97 deletions

File tree

.envrc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
GOPATH=$(pwd)
2-
export GOPATH
31
PATH_add tools
42

5-
6-
WORKSPACE_ROOT=$(pwd)
7-
export WORKSPACE_ROOT
3+
REPO_ROOT=$(pwd)
4+
export REPO_ROOT

.github/workflows/build_and_test.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ on:
99
- opened
1010
- reopened
1111
- synchronize
12-
- ready_for_review
1312

1413
jobs:
1514
build-and-test:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ MODULE.bazel.lock
55
.vscode/
66
.idea/
77
.claude/
8+
.ijwb/
89

910

1011
# Built binaries

MODULE.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ go_deps.from_file(go_mod = "//:go.mod")
3737
use_repo(
3838
go_deps,
3939
"com_github_gogo_protobuf",
40+
"com_github_uber_go_tally_v4",
4041
"org_golang_google_grpc",
4142
"org_golang_google_protobuf",
4243
"org_uber_go_fx",
4344
"org_uber_go_yarpc",
45+
"org_uber_go_zap",
4446
)

README.md

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,23 @@ For detailed instructions, see [examples/README.md](examples/README.md).
5050

5151
See [docs/architecture/STRUCTURE.md](docs/architecture/STRUCTURE.md) for a detailed breakdown of the project structure.
5252

53+
## Architecture
54+
55+
The project follows clean architecture principles with clear separation of concerns:
56+
57+
- **Controllers** (`core/controller/`): Pure business logic, independent of transport layer
58+
- Only depend on logger, metrics, and protobuf types
59+
- Example: `PingController` handles ping business logic
60+
61+
- **Server Adapters** (`examples/server/`): gRPC transport layer
62+
- Wrap controllers and implement gRPC service interfaces
63+
- Handle protocol-specific concerns (e.g., `UnimplementedServiceServer`)
64+
65+
- **Observability**: Built-in logging and metrics
66+
- Structured logging with [Zap](https://github.com/uber-go/zap)
67+
- Metrics collection with [Tally](https://github.com/uber-go/tally)
68+
- Development servers use human-readable console logging
69+
5370
## Development
5471

5572
### Prerequisites
@@ -226,7 +243,8 @@ message PingResponse {
226243
string message = 1;
227244
string service_name = 2;
228245
int64 timestamp = 3;
229-
string hostname = 4; // New field added
246+
string hostname = 4;
247+
string new_field = 5; // New field added
230248
}
231249
```
232250

@@ -240,8 +258,8 @@ make proto
240258
# - gateway/protopb/gateway_grpc.pb.go
241259
# - gateway/protopb/gateway.pb.yarpc.go
242260

243-
# Now update the service implementation
244-
# Edit gateway/core/controller/ping.go to populate the hostname field
261+
# Now update the controller implementation
262+
# Edit gateway/core/controller/ping.go to populate the new field in the PingResponse
245263
```
246264

247265
### Testing
@@ -313,17 +331,44 @@ make test
313331
make proto
314332
```
315333

316-
3. **Implement the method in the service:**
334+
3. **Implement the method in the controller:**
335+
```go
336+
// In gateway/core/controller/ (create a new controller file)
337+
type NewController struct {
338+
logger *zap.Logger
339+
metricsScope tally.Scope
340+
}
341+
342+
func NewNewController(logger *zap.Logger, scope tally.Scope) *NewController {
343+
if logger == nil {
344+
logger = zap.NewNop()
345+
}
346+
if scope == nil {
347+
scope = tally.NoopScope
348+
}
349+
return &NewController{logger: logger, metricsScope: scope}
350+
}
351+
352+
func (c *NewController) NewMethod(ctx context.Context, req *pb.NewRequest) (*pb.NewResponse, error) {
353+
// Business logic here
354+
c.logger.Info("new method called")
355+
c.metricsScope.Counter("new_method_total").Inc(1)
356+
// ...
357+
}
358+
```
359+
360+
4. **Create server wrapper in example:**
317361
```go
318-
// In gateway/core/controller/ping.go (or create a new file)
319-
func (s *PingServiceImpl) NewMethod(ctx context.Context, req *pb.NewRequest) (*pb.NewResponse, error) {
320-
// Implementation here
362+
// In examples/server/gateway/main.go
363+
// Add method delegation to GatewayServer struct:
364+
func (s *GatewayServer) NewMethod(ctx context.Context, req *pb.NewRequest) (*pb.NewResponse, error) {
365+
return s.newController.NewMethod(ctx, req)
321366
}
322367
```
323368

324-
4. **Update clients to call the new method**
369+
5. **Update clients to call the new method**
325370

326-
5. **Rebuild and test:**
371+
6. **Rebuild and test:**
327372
```bash
328373
make build
329374
```

examples/server/gateway/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ go_library(
88
deps = [
99
"//gateway/core/controller",
1010
"//gateway/protopb",
11+
"@com_github_uber_go_tally_v4//:tally",
1112
"@org_golang_google_grpc//:grpc",
1213
"@org_golang_google_grpc//reflection",
14+
"@org_uber_go_zap//:zap",
1315
],
1416
)
1517

examples/server/gateway/main.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"os"
78
"os/signal"
89
"syscall"
10+
"time"
911

12+
"github.com/uber-go/tally/v4"
1013
"github.com/uber/submitqueue/gateway/core/controller"
1114
pb "github.com/uber/submitqueue/gateway/protopb"
15+
"go.uber.org/zap"
1216
"google.golang.org/grpc"
1317
"google.golang.org/grpc/reflection"
1418
)
1519

20+
// GatewayServer wraps the controller and implements the gRPC service interface
21+
type GatewayServer struct {
22+
pb.UnimplementedGatewayServiceServer
23+
controller *controller.PingController
24+
}
25+
26+
// Ping delegates to the controller
27+
func (s *GatewayServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) {
28+
return s.controller.Ping(ctx, req)
29+
}
30+
1631
func main() {
1732
if err := run(); err != nil {
1833
fmt.Fprintf(os.Stderr, "Failed to start gateway server: %v\n", err)
@@ -21,12 +36,37 @@ func main() {
2136
}
2237

2338
func run() error {
39+
// Initialize development logger (human-readable console output)
40+
logger, err := zap.NewDevelopment()
41+
if err != nil {
42+
return fmt.Errorf("failed to create logger: %w", err)
43+
}
44+
defer logger.Sync()
45+
46+
// Initialize metrics scope
47+
scope := tally.NewTestScope("gateway", nil)
48+
go func() {
49+
ticker := time.NewTicker(10 * time.Second)
50+
defer ticker.Stop()
51+
for range ticker.C {
52+
snapshot := scope.Snapshot()
53+
logger.Info("metrics snapshot",
54+
zap.Any("counters", snapshot.Counters()),
55+
zap.Any("gauges", snapshot.Gauges()),
56+
zap.Any("timers", snapshot.Timers()),
57+
)
58+
}
59+
}()
60+
2461
// Create gRPC server
2562
grpcServer := grpc.NewServer()
2663

27-
// Register the ping service
28-
pingService := controller.NewPingService()
29-
pb.RegisterGatewayServiceServer(grpcServer, pingService)
64+
// Create ping controller and wrap it for gRPC
65+
pingController := controller.NewPingController(logger, scope)
66+
gatewayServer := &GatewayServer{
67+
controller: pingController,
68+
}
69+
pb.RegisterGatewayServiceServer(grpcServer, gatewayServer)
3070

3171
// Register reflection service for debugging with grpcurl
3272
reflection.Register(grpcServer)

examples/server/orchestrator/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ go_library(
88
deps = [
99
"//orchestrator/core/controller",
1010
"//orchestrator/protopb",
11+
"@com_github_uber_go_tally_v4//:tally",
1112
"@org_golang_google_grpc//:grpc",
1213
"@org_golang_google_grpc//reflection",
14+
"@org_uber_go_zap//:zap",
1315
],
1416
)
1517

examples/server/orchestrator/main.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
package main
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"os"
78
"os/signal"
89
"syscall"
10+
"time"
911

12+
"github.com/uber-go/tally/v4"
1013
"github.com/uber/submitqueue/orchestrator/core/controller"
1114
pb "github.com/uber/submitqueue/orchestrator/protopb"
15+
"go.uber.org/zap"
1216
"google.golang.org/grpc"
1317
"google.golang.org/grpc/reflection"
1418
)
1519

20+
// OrchestratorServer wraps the controller and implements the gRPC service interface
21+
type OrchestratorServer struct {
22+
pb.UnimplementedOrchestratorServiceServer
23+
controller *controller.PingController
24+
}
25+
26+
// Ping delegates to the controller
27+
func (s *OrchestratorServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) {
28+
return s.controller.Ping(ctx, req)
29+
}
30+
1631
func main() {
1732
if err := run(); err != nil {
1833
fmt.Fprintf(os.Stderr, "Failed to start orchestrator server: %v\n", err)
@@ -21,12 +36,37 @@ func main() {
2136
}
2237

2338
func run() error {
39+
// Initialize development logger (human-readable console output)
40+
logger, err := zap.NewDevelopment()
41+
if err != nil {
42+
return fmt.Errorf("failed to create logger: %w", err)
43+
}
44+
defer logger.Sync()
45+
46+
// Initialize metrics scope
47+
scope := tally.NewTestScope("orchestrator", nil)
48+
go func() {
49+
ticker := time.NewTicker(10 * time.Second)
50+
defer ticker.Stop()
51+
for range ticker.C {
52+
snapshot := scope.Snapshot()
53+
logger.Info("metrics snapshot",
54+
zap.Any("counters", snapshot.Counters()),
55+
zap.Any("gauges", snapshot.Gauges()),
56+
zap.Any("timers", snapshot.Timers()),
57+
)
58+
}
59+
}()
60+
2461
// Create gRPC server
2562
grpcServer := grpc.NewServer()
2663

27-
// Register the ping service
28-
pingService := controller.NewPingService()
29-
pb.RegisterOrchestratorServiceServer(grpcServer, pingService)
64+
// Create ping controller and wrap it for gRPC
65+
pingController := controller.NewPingController(logger, scope)
66+
orchestratorServer := &OrchestratorServer{
67+
controller: pingController,
68+
}
69+
pb.RegisterOrchestratorServiceServer(grpcServer, orchestratorServer)
3070

3171
// Register reflection service for debugging with grpcurl
3272
reflection.Register(grpcServer)

examples/server/speculator/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ go_library(
88
deps = [
99
"//speculator/core/controller",
1010
"//speculator/protopb",
11+
"@com_github_uber_go_tally_v4//:tally",
1112
"@org_golang_google_grpc//:grpc",
1213
"@org_golang_google_grpc//reflection",
14+
"@org_uber_go_zap//:zap",
1315
],
1416
)
1517

0 commit comments

Comments
 (0)