@@ -6,17 +6,23 @@ import (
66 "fmt"
77 "net"
88 "net/http"
9+ "os"
10+ "os/signal"
911 "strings"
12+ "syscall"
1013
1114 "paperdebugger/internal/libs/logger"
1215 "paperdebugger/internal/libs/metadatautil"
1316 "paperdebugger/internal/libs/shared"
17+ "paperdebugger/internal/services"
18+ aiclient "paperdebugger/internal/services/toolkit/client"
1419 authv1 "paperdebugger/pkg/gen/api/auth/v1"
1520 chatv1 "paperdebugger/pkg/gen/api/chat/v1"
1621 chatv2 "paperdebugger/pkg/gen/api/chat/v2"
1722 commentv1 "paperdebugger/pkg/gen/api/comment/v1"
1823 projectv1 "paperdebugger/pkg/gen/api/project/v1"
1924 sharedv1 "paperdebugger/pkg/gen/api/shared/v1"
25+ usagev1 "paperdebugger/pkg/gen/api/usage/v1"
2026 userv1 "paperdebugger/pkg/gen/api/user/v1"
2127
2228 "github.com/gin-gonic/gin"
@@ -30,25 +36,37 @@ import (
3036)
3137
3238type Server struct {
33- grpcServer * GrpcServer
34- ginServer * GinServer
39+ grpcServer * GrpcServer
40+ ginServer * GinServer
41+ pricingService * services.PricingService
42+ aiClientV2 * aiclient.AIClientV2
3543
3644 logger * logger.Logger
3745}
3846
3947func NewServer (
4048 grpcServer * GrpcServer ,
4149 ginServer * GinServer ,
50+ pricingService * services.PricingService ,
51+ aiClientV2 * aiclient.AIClientV2 ,
4252 logger * logger.Logger ,
4353) * Server {
4454 return & Server {
45- grpcServer : grpcServer ,
46- ginServer : ginServer ,
47- logger : logger ,
55+ grpcServer : grpcServer ,
56+ ginServer : ginServer ,
57+ pricingService : pricingService ,
58+ aiClientV2 : aiClientV2 ,
59+ logger : logger ,
4860 }
4961}
5062
5163func (s * Server ) Run (addr string ) {
64+ // Start the pricing updater in the background
65+ ctx , cancel := context .WithCancel (context .Background ())
66+ defer cancel ()
67+
68+ s .pricingService .StartPriceUpdater (ctx )
69+
5270 listener , err := net .Listen ("tcp" , ":0" )
5371 if err != nil {
5472 s .logger .Fatalf ("failed to start grpc server listener: %v" , err )
@@ -105,6 +123,22 @@ func (s *Server) Run(addr string) {
105123 s .logger .Fatalf ("failed to register comment service grpc gateway: %v" , err )
106124 return
107125 }
126+ err = usagev1 .RegisterUsageServiceHandler (context .Background (), mux , client )
127+ if err != nil {
128+ s .logger .Fatalf ("failed to register usage service grpc gateway: %v" , err )
129+ return
130+ }
131+
132+ // Set up signal handling for graceful shutdown
133+ sigChan := make (chan os.Signal , 1 )
134+ signal .Notify (sigChan , syscall .SIGINT , syscall .SIGTERM )
135+
136+ go func () {
137+ <- sigChan
138+ s .logger .Info ("[PAPERDEBUGGER] received shutdown signal, shutting down gracefully..." )
139+ s .Shutdown ()
140+ os .Exit (0 )
141+ }()
108142
109143 s .logger .Infof ("[PAPERDEBUGGER] http server listening on %s" , addr )
110144 s .ginServer .Any ("/_pd/api/*path" , func (c * gin.Context ) { mux .ServeHTTP (c .Writer , c .Request ) })
@@ -114,6 +148,16 @@ func (s *Server) Run(addr string) {
114148 }
115149}
116150
151+ // Shutdown gracefully shuts down all server components.
152+ func (s * Server ) Shutdown () {
153+ s .logger .Info ("[PAPERDEBUGGER] shutting down AI client (draining usage records)..." )
154+ s .aiClientV2 .Shutdown ()
155+ s .logger .Info ("[PAPERDEBUGGER] AI client shutdown complete" )
156+
157+ s .grpcServer .GracefulStop ()
158+ s .logger .Info ("[PAPERDEBUGGER] gRPC server shutdown complete" )
159+ }
160+
117161func (s * Server ) metadataAnnotator () func (ctx context.Context , req * http.Request ) metadata.MD {
118162 return func (ctx context.Context , req * http.Request ) metadata.MD {
119163 md := metadata .New (map [string ]string {})
0 commit comments