services.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package service
  15. import (
  16. "fmt"
  17. "os"
  18. "path/filepath"
  19. "strconv"
  20. "syscall"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/util/signalutils"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/options"
  25. "yunion.io/x/onecloud/pkg/util/fileutils2"
  26. "yunion.io/x/onecloud/pkg/util/procutils"
  27. )
  28. type IService interface {
  29. InitService()
  30. RunService()
  31. OnExitService()
  32. }
  33. type SServiceBase struct {
  34. Service IService
  35. O *options.BaseOptions
  36. }
  37. func NewBaseService(service IService) *SServiceBase {
  38. return &SServiceBase{Service: service}
  39. }
  40. func (s *SServiceBase) StartService() {
  41. defer s.Service.OnExitService()
  42. defer s.RemovePid()
  43. s.Service.InitService()
  44. if err := s.CreatePid(); err != nil {
  45. log.Fatalln(err)
  46. }
  47. s.Service.RunService()
  48. }
  49. func (s *SServiceBase) CreatePid() error {
  50. if s.O == nil || len(s.O.PidFile) == 0 {
  51. return nil
  52. }
  53. absPath, err := filepath.Abs(s.O.PidFile)
  54. if err != nil {
  55. return fmt.Errorf("Get pidfile %s absolute path failed: %s", s.O.PidFile, err)
  56. }
  57. s.O.PidFile = absPath
  58. pidDir := filepath.Dir(s.O.PidFile)
  59. if !fileutils2.Exists(pidDir) {
  60. output, err := procutils.NewCommand("mkdir", "-p", pidDir).Output()
  61. if err != nil {
  62. return fmt.Errorf("Make pid dir %s failed: %s", pidDir, output)
  63. }
  64. }
  65. err = fileutils2.FilePutContents(s.O.PidFile, strconv.Itoa(os.Getpid()), false)
  66. if err != nil {
  67. return fmt.Errorf("Write pidfile %s failed: %s", s.O.PidFile, err)
  68. }
  69. return nil
  70. }
  71. func (s *SServiceBase) RemovePid() {
  72. if s.O != nil && len(s.O.PidFile) > 0 && fileutils2.Exists(s.O.PidFile) {
  73. os.Remove(s.O.PidFile)
  74. }
  75. }
  76. func (s *SServiceBase) SignalTrap(onExit func()) {
  77. // dump goroutine stack
  78. signalutils.RegisterSignal(func() {
  79. utils.DumpAllGoroutineStack(log.Logger().Out)
  80. }, syscall.SIGUSR1)
  81. if onExit != nil {
  82. quitSignals := []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM}
  83. signalutils.RegisterSignal(onExit, quitSignals...)
  84. }
  85. signalutils.StartTrap()
  86. }