blob: 3bdc1f98690fef4eaae645502e739192abf53cb3 [file] [log] [blame]
Hendrik Hofstadt0d7c91e2019-10-23 21:44:47 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package common
18
19import (
20 "errors"
21 "go.uber.org/zap"
22 "sync"
23)
24
25var (
26 ErrAlreadyRunning = errors.New("service is already running")
27 ErrNotRunning = errors.New("service is not running")
28)
29
30type (
31 // Service represents a subsystem of an application that can be used with a BaseService.
32 Service interface {
33 OnStart() error
34 OnStop() error
35 }
36
37 // BaseService implements utility functionality around a service.
38 BaseService struct {
39 impl Service
40 name string
41
42 Logger *zap.Logger
43
44 mutex sync.Mutex
45 running bool
46 }
47)
48
49func NewBaseService(name string, logger *zap.Logger, impl Service) *BaseService {
50 return &BaseService{
51 Logger: logger,
52 name: name,
53 impl: impl,
54 }
55}
56
57// Start starts the service. This is an atomic operation and should not be called on an already running service.
58func (b *BaseService) Start() error {
59 b.mutex.Lock()
60 defer b.mutex.Unlock()
61
62 if b.running {
63 return ErrAlreadyRunning
64 }
65
66 err := b.impl.OnStart()
67 if err != nil {
68 b.Logger.Error("Failed to start service", zap.String("service", b.name), zap.Error(err))
69 return err
70 }
71
72 b.running = true
73 b.Logger.Info("Started service", zap.String("service", b.name))
74 return nil
75}
76
77// Stop stops the service. THis is an atomic operation and should only be called on a running service.
78func (b *BaseService) Stop() error {
79 b.mutex.Lock()
80 defer b.mutex.Unlock()
81
82 if !b.running {
83 return ErrNotRunning
84 }
85
86 err := b.impl.OnStart()
87 if err != nil {
88 b.Logger.Error("Failed to stop service", zap.String("service", b.name), zap.Error(err))
89
90 return err
91 }
92
93 b.running = false
94 b.Logger.Info("Stopped service", zap.String("service", b.name))
95 return nil
96}
97
98// IsRunning returns whether the service is currently running.
99func (b *BaseService) IsRunning() bool {
100 b.mutex.Lock()
101 defer b.mutex.Unlock()
102
103 return b.running
104}