name support & slight changes in business logic

This commit is contained in:
Pavel 2022-12-29 00:03:40 +03:00
parent 7bff09f467
commit 1c6689583a
4 changed files with 31 additions and 14 deletions

View File

@ -12,6 +12,7 @@ const DefaultResetPeriod = time.Minute * 15
// AtomicCounter is a default Counter implementation. // AtomicCounter is a default Counter implementation.
// It uses atomics under the hood (hence the name) and can be configured with custom reset timeout and // It uses atomics under the hood (hence the name) and can be configured with custom reset timeout and
type AtomicCounter struct { type AtomicCounter struct {
name atomic.String
msg atomic.String msg atomic.String
timestamp atomic.Time timestamp atomic.Time
resetPeriod time.Duration resetPeriod time.Duration
@ -23,16 +24,25 @@ type AtomicCounter struct {
} }
// NewAtomicCounterWithPeriod returns AtomicCounter configured with provided period. // NewAtomicCounterWithPeriod returns AtomicCounter configured with provided period.
func NewAtomicCounterWithPeriod(resetPeriod time.Duration) Counter { func NewAtomicCounterWithPeriod(name string, resetPeriod time.Duration) Counter {
c := &AtomicCounter{} c := &AtomicCounter{}
c.SetName(name)
c.resetPeriod = resetPeriod c.resetPeriod = resetPeriod
c.timestamp.Store(time.Now()) c.timestamp.Store(time.Now())
return c return c
} }
// NewAtomicCounter returns AtomicCounter with DefaultResetPeriod. // NewAtomicCounter returns AtomicCounter with DefaultResetPeriod.
func NewAtomicCounter() Counter { func NewAtomicCounter(name string) Counter {
return NewAtomicCounterWithPeriod(DefaultResetPeriod) return NewAtomicCounterWithPeriod(name, DefaultResetPeriod)
}
func (a *AtomicCounter) Name() string {
return a.name.Load()
}
func (a *AtomicCounter) SetName(name string) {
a.name.Store(name)
} }
func (a *AtomicCounter) HitSuccess() { func (a *AtomicCounter) HitSuccess() {

View File

@ -3,7 +3,8 @@ package health
// Storage stores different instances of Counter. Implementation should be goroutine-safe. // Storage stores different instances of Counter. Implementation should be goroutine-safe.
type Storage interface { type Storage interface {
// Get counter by its ID. The counter will be instantiated automatically if necessary. // Get counter by its ID. The counter will be instantiated automatically if necessary.
Get(id int) Counter // Name here is not used to identify the counter in the storage.
Get(id int, name string) Counter
// Remove counter if it exists. // Remove counter if it exists.
Remove(id int) Remove(id int)
// Process will iterate over counters and call Processor on each of them. // Process will iterate over counters and call Processor on each of them.
@ -15,6 +16,10 @@ type Storage interface {
// is not working properly (invalid credentials, too many failed requests, etc) and take further action based on the result. // is not working properly (invalid credentials, too many failed requests, etc) and take further action based on the result.
// Implementation should be goroutine-safe. // Implementation should be goroutine-safe.
type Counter interface { type Counter interface {
// Name can be used as a more friendly identifier for the counter.
Name() string
// SetName of the counter.
SetName(name string)
// HitSuccess registers successful request. It should automatically clear error state because that state should be // HitSuccess registers successful request. It should automatically clear error state because that state should be
// used only if error is totally unrecoverable. // used only if error is totally unrecoverable.
HitSuccess() HitSuccess()
@ -55,8 +60,8 @@ type Processor interface {
// NotifyMessageLocalizer is the smallest subset of core.Localizer used in the // NotifyMessageLocalizer is the smallest subset of core.Localizer used in the
type NotifyMessageLocalizer interface { type NotifyMessageLocalizer interface {
SetLocale(string) SetLocale(locale string)
GetLocalizedMessage(string) string GetLocalizedTemplateMessage(messageID string, templateData map[string]interface{}) string
} }
// NotifyFunc will send notification about error to the system with provided credentials. // NotifyFunc will send notification about error to the system with provided credentials.
@ -64,7 +69,7 @@ type NotifyMessageLocalizer interface {
type NotifyFunc func(apiURL, apiKey, msg string) type NotifyFunc func(apiURL, apiKey, msg string)
// CounterConstructor is used to create counters. This way you can implement your own counter and still use default CounterStorage. // CounterConstructor is used to create counters. This way you can implement your own counter and still use default CounterStorage.
type CounterConstructor func() Counter type CounterConstructor func(name string) Counter
// ConnectionDataProvider should return the connection credentials and language by counter ID. // ConnectionDataProvider should return the connection credentials and language by counter ID.
// It's best to use account ID as a counter ID to be able to retrieve the necessary data as easy as possible. // It's best to use account ID as a counter ID to be able to retrieve the necessary data as easy as possible.

View File

@ -26,8 +26,8 @@ func (c CounterProcessor) Process(id int, counter Counter) {
return return
} }
apiURL, apiKey, lang := c.ConnectionDataProvider(id) apiURL, apiKey, _ := c.ConnectionDataProvider(id)
c.Notifier(apiURL, apiKey, c.getErrorText(counter.Message(), lang)) c.Notifier(apiURL, apiKey, counter.Message())
counter.FailureProcessed() counter.FailureProcessed()
return return
} }
@ -55,15 +55,15 @@ func (c CounterProcessor) Process(id int, counter Counter) {
} }
apiURL, apiKey, lang := c.ConnectionDataProvider(id) apiURL, apiKey, lang := c.ConnectionDataProvider(id)
c.Notifier(apiURL, apiKey, c.getErrorText(c.Error, lang)) c.Notifier(apiURL, apiKey, c.getErrorText(counter.Name(), c.Error, lang))
counter.CountersProcessed() counter.CountersProcessed()
return return
} }
func (c CounterProcessor) getErrorText(msg, lang string) string { func (c CounterProcessor) getErrorText(name, msg, lang string) string {
if c.Localizer == nil { if c.Localizer == nil {
return msg return msg
} }
c.Localizer.SetLocale(lang) c.Localizer.SetLocale(lang)
return c.Localizer.GetLocalizedMessage(msg) return c.Localizer.GetLocalizedTemplateMessage(msg, map[string]interface{}{"Name": name})
} }

View File

@ -15,12 +15,14 @@ func NewSyncMapStorage(constructor CounterConstructor) Storage {
return &SyncMapStorage{constructor: constructor} return &SyncMapStorage{constructor: constructor}
} }
func (s *SyncMapStorage) Get(id int) Counter { func (s *SyncMapStorage) Get(id int, name string) Counter {
val, found := s.m.Load(id) val, found := s.m.Load(id)
if found { if found {
counter := val.(Counter)
counter.SetName(name)
return val.(Counter) return val.(Counter)
} }
c := s.constructor() c := s.constructor(name)
s.m.Store(id, c) s.m.Store(id, c)
return c return c
} }