mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-11 14:20:32 +01:00
Notifications
The notif package provides a notification dispatching system for GoDoxy, supporting multiple providers (Webhook, Gotify, Ntfy) with retry logic and exponential backoff.
Overview
The notif package implements a notification dispatcher that delivers messages to multiple providers with automatic retry handling, provider management, and logging support.
Key Features
- Multiple notification providers (Webhook, Gotify, Ntfy)
- Provider registration and management
- Retry logic with exponential backoff
- Message queuing with configurable buffer
- Selective provider targeting
- Colored message support
Architecture
graph TD
A[LogMessage] --> B[Dispatcher]
B --> C{Provider Filter}
C -->|Matches| D[Send to Provider]
C -->|No Match| E[Skip]
D --> F{Send Success?}
F -->|Yes| G[Log Success]
F -->|No| H[Retry Queue]
H --> I{Retry Limit?}
I -->|No| J[Schedule Retry]
J --> B
I -->|Yes| K[Log Failure]
subgraph Providers
L[Webhook]
M[Gotify]
N[Ntfy]
end
D --> L
D --> M
D --> N
Core Components
Dispatcher
type Dispatcher struct {
task *task.Task
providers *xsync.Map[Provider, struct{}]
logCh chan *LogMessage
retryMsg *xsync.Map[*RetryMessage, struct{}]
retryTicker *time.Ticker
}
LogMessage
type LogMessage struct {
Level zerolog.Level
Title string
Body LogBody
Color Color
To []string // Provider names to target
}
type LogBody []string
Provider Interface
type Provider interface {
GetName() string
Send(ctx context.Context, msg *LogMessage) error
}
Providers
Webhook
type Webhook struct {
URL string `json:"url"`
Method string `json:"method"` // default: POST
}
Gotify
type GotifyClient struct {
URL string `json:"url"`
Token string `json:"token"`
}
Ntfy
type Ntfy struct {
URL string `json:"url"`
Topic string `json:"topic"`
}
Public API
Dispatcher Management
// StartNotifDispatcher initializes the notification dispatcher.
func StartNotifDispatcher(parent task.Parent) *Dispatcher
Notification
// Notify sends a log message to all providers.
func Notify(msg *LogMessage)
Dispatcher Methods
// RegisterProvider registers a notification provider.
func (disp *Dispatcher) RegisterProvider(cfg *NotificationConfig)
Usage
Basic Notification
notif.Notify(¬if.LogMessage{
Level: zerolog.InfoLevel,
Title: "Container Started",
Body: notif.ListBody{
"Container: myapp",
"Status: Running",
},
})
Provider-Specific Notification
notif.Notify(¬if.LogMessage{
Level: zerolog.WarnLevel,
Title: "High Memory Usage",
Body: notif.MessageBody("Memory: 85%"),
Color: notif.ColorRed,
To: []string{"gotify"}, // Only send to provider with name "gotify"
})
Registering Providers
dispatcher := notif.StartNotifDispatcher(parent)
dispatcher.RegisterProvider(¬if.NotificationConfig{
ProviderName: notif.ProviderWebhook,
Provider: ¬if.Webhook{
URL: "https://hooks.example.com/webhook",
},
})
dispatcher.RegisterProvider(¬if.NotificationConfig{
ProviderName: notif.ProviderGotify,
Provider: ¬if.GotifyClient{
URL: "https://gotify.example.com",
Token: "secret",
},
})
Retry Logic
Configuration
const (
retryInterval = time.Second
maxBackoffDelay = 5 * time.Minute
backoffMultiplier = 2.0
)
Backoff Calculation
func calculateBackoffDelay(trials int) time.Duration {
if trials == 0 {
return retryInterval
}
delay := min(float64(retryInterval)*math.Pow(backoffMultiplier, float64(trials)),
float64(maxBackoffDelay))
// Add 20% jitter
jitter := delay * 0.2 * (rand.Float64() - 0.5)
return time.Duration(delay + jitter)
}
Retry Schedule
| Trial | Delay | Jitter | Total (approx) |
|---|---|---|---|
| 0 | 1s | +/- 100ms | 0.9-1.1s |
| 1 | 2s | +/- 200ms | 1.8-2.2s |
| 2 | 4s | +/- 400ms | 3.6-4.4s |
| 3 | 8s | +/- 800ms | 7.2-8.8s |
| 4 | 16s | +/- 1.6s | 14.4-17.6s |
| 5 | 32s | +/- 3.2s | 28.8-35.2s |
| ... | max 5m | +/- 30s | 4.5-5.5m |
Data Flow
sequenceDiagram
participant App
participant Dispatcher
participant Queue
participant Provider
participant RetryScheduler
App->>Dispatcher: Notify(LogMessage)
Dispatcher->>Dispatcher: Buffer Message
Dispatcher->>Dispatcher: Dispatch Async
par Parallel Provider Delivery
Dispatcher->>Provider: Send()
alt Success
Provider-->>Dispatcher: nil
Dispatcher->>Dispatcher: Log Success
else Failure
Provider-->>Dispatcher: Error
Dispatcher->>RetryScheduler: Schedule Retry
end
end
loop Retry Ticker
RetryScheduler->>Dispatcher: Process Retries
Dispatcher->>Provider: Retry Send
end
Message Colors
type Color uint
const (
ColorDefault Color = iota
ColorRed
ColorGreen
ColorBlue
ColorYellow
ColorPurple
)
Configuration
YAML Configuration
providers:
notification:
- provider: webhook
url: https://hooks.example.com/webhook
method: POST
- provider: gotify
url: https://gotify.example.com
token: your-token
- provider: ntfy
url: https://ntfy.example.com
topic: godoxy
Integration Points
The notif package integrates with:
- ACL: Blocked access notifications
- Route: Route status changes
- Idlewatcher: Container idle/alive notifications
- Health: Health check alerts
- Autocert: Certificate expiration warnings
Error Handling
Provider Errors
var (
ErrMissingNotifProvider = gperr.New("missing notification provider")
ErrInvalidNotifProviderType = gperr.New("invalid notification provider type")
ErrUnknownNotifProvider = gperr.New("unknown notification provider")
)
Retry Limits
Retry limits depend on message level:
var maxRetries = map[zerolog.Level]int{
zerolog.ErrorLevel: 3,
zerolog.WarnLevel: 2,
zerolog.InfoLevel: 1,
zerolog.DebugLevel: 0,
}
Performance Considerations
- Buffered channel with 100 message capacity
- Non-blocking sends to provider
- Batched retry processing
- Provider filtering reduces unnecessary calls
- Exponential backoff prevents thundering herd