github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/service/daemon/server.go (about) 1 package daemon 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/mutagen-io/mutagen/pkg/housekeeping" 8 "github.com/mutagen-io/mutagen/pkg/mutagen" 9 ) 10 11 const ( 12 // housekeepingInterval is the interval at which housekeeping will be 13 // invoked by the daemon. 14 housekeepingInterval = 24 * time.Hour 15 ) 16 17 // Server provides an implementation of the Daemon service. 18 type Server struct { 19 // UnimplementedDaemonServer is the required base implementation. 20 UnimplementedDaemonServer 21 // Termination is populated with requests from clients invoking the shutdown 22 // method over RPC. It can be ignored by daemon host processes wishing to 23 // ignore temination requests originating from clients. The channel is 24 // buffered and non-blocking, so it doesn't need to be serviced by the 25 // daemon host-process at all - additional incoming shutdown requests will 26 // just bounce off once the channel is populated. We do this, instead of 27 // closing the channel, because we can't close the channel multiple times. 28 Termination chan struct{} 29 // workerCtx is the context regulating the server's internal operations. 30 workerCtx context.Context 31 // shutdown is the context cancellation function for the server's internal 32 // operation context. 33 shutdown context.CancelFunc 34 } 35 36 // NewServer creates a new daemon server. 37 func NewServer() *Server { 38 // Create a cancellable context for daemon background operations. 39 workerCtx, shutdown := context.WithCancel(context.Background()) 40 41 // Create the server. 42 server := &Server{ 43 Termination: make(chan struct{}, 1), 44 workerCtx: workerCtx, 45 shutdown: shutdown, 46 } 47 48 // Start the housekeeping Goroutine. 49 go server.housekeep() 50 51 // Done. 52 return server 53 } 54 55 // housekeep provides regular housekeeping facilities for the daemon. 56 func (s *Server) housekeep() { 57 // Perform an initial housekeeping operation since the ticker won't fire 58 // straight away. 59 housekeeping.Housekeep() 60 61 // Create a ticker to regulate housekeeping and defer its shutdown. 62 ticker := time.NewTicker(housekeepingInterval) 63 defer ticker.Stop() 64 65 // Loop and wait for the ticker or cancellation. 66 for { 67 select { 68 case <-s.workerCtx.Done(): 69 return 70 case <-ticker.C: 71 housekeeping.Housekeep() 72 } 73 } 74 } 75 76 // Shutdown gracefully shuts down server resources. 77 func (s *Server) Shutdown() { 78 // Cancel all internal operations. 79 s.shutdown() 80 } 81 82 // Version provides version information. 83 func (s *Server) Version(_ context.Context, _ *VersionRequest) (*VersionResponse, error) { 84 return &VersionResponse{ 85 Major: mutagen.VersionMajor, 86 Minor: mutagen.VersionMinor, 87 Patch: mutagen.VersionPatch, 88 Tag: mutagen.VersionTag, 89 }, nil 90 } 91 92 // Terminate requests daemon termination. 93 func (s *Server) Terminate(_ context.Context, _ *TerminateRequest) (*TerminateResponse, error) { 94 // Send the termination request in a non-blocking manner. 95 select { 96 case s.Termination <- struct{}{}: 97 default: 98 } 99 100 // Success. 101 return &TerminateResponse{}, nil 102 }