mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-23 01:08:47 +02:00
docs: add per package README for implementation details (AI generated with human review)
This commit is contained in:
332
internal/notif/README.md
Normal file
332
internal/notif/README.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# 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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```go
|
||||
type Dispatcher struct {
|
||||
task *task.Task
|
||||
providers *xsync.Map[Provider, struct{}]
|
||||
logCh chan *LogMessage
|
||||
retryMsg *xsync.Map[*RetryMessage, struct{}]
|
||||
retryTicker *time.Ticker
|
||||
}
|
||||
```
|
||||
|
||||
### LogMessage
|
||||
|
||||
```go
|
||||
type LogMessage struct {
|
||||
Level zerolog.Level
|
||||
Title string
|
||||
Body LogBody
|
||||
Color Color
|
||||
To []string // Provider names to target
|
||||
}
|
||||
|
||||
type LogBody []string
|
||||
```
|
||||
|
||||
### Provider Interface
|
||||
|
||||
```go
|
||||
type Provider interface {
|
||||
GetName() string
|
||||
Send(ctx context.Context, msg *LogMessage) error
|
||||
}
|
||||
```
|
||||
|
||||
## Providers
|
||||
|
||||
### Webhook
|
||||
|
||||
```go
|
||||
type Webhook struct {
|
||||
URL string `json:"url"`
|
||||
Method string `json:"method"` // default: POST
|
||||
}
|
||||
```
|
||||
|
||||
### Gotify
|
||||
|
||||
```go
|
||||
type GotifyClient struct {
|
||||
URL string `json:"url"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
```
|
||||
|
||||
### Ntfy
|
||||
|
||||
```go
|
||||
type Ntfy struct {
|
||||
URL string `json:"url"`
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
```
|
||||
|
||||
## Public API
|
||||
|
||||
### Dispatcher Management
|
||||
|
||||
```go
|
||||
// StartNotifDispatcher initializes the notification dispatcher.
|
||||
func StartNotifDispatcher(parent task.Parent) *Dispatcher
|
||||
```
|
||||
|
||||
### Notification
|
||||
|
||||
```go
|
||||
// Notify sends a log message to all providers.
|
||||
func Notify(msg *LogMessage)
|
||||
```
|
||||
|
||||
### Dispatcher Methods
|
||||
|
||||
```go
|
||||
// RegisterProvider registers a notification provider.
|
||||
func (disp *Dispatcher) RegisterProvider(cfg *NotificationConfig)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Notification
|
||||
|
||||
```go
|
||||
notif.Notify(¬if.LogMessage{
|
||||
Level: zerolog.InfoLevel,
|
||||
Title: "Container Started",
|
||||
Body: notif.ListBody{
|
||||
"Container: myapp",
|
||||
"Status: Running",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Provider-Specific Notification
|
||||
|
||||
```go
|
||||
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
|
||||
|
||||
```go
|
||||
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
|
||||
|
||||
```go
|
||||
const (
|
||||
retryInterval = time.Second
|
||||
maxBackoffDelay = 5 * time.Minute
|
||||
backoffMultiplier = 2.0
|
||||
)
|
||||
```
|
||||
|
||||
### Backoff Calculation
|
||||
|
||||
```go
|
||||
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
|
||||
|
||||
```mermaid
|
||||
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
|
||||
|
||||
```go
|
||||
type Color uint
|
||||
|
||||
const (
|
||||
ColorDefault Color = iota
|
||||
ColorRed
|
||||
ColorGreen
|
||||
ColorBlue
|
||||
ColorYellow
|
||||
ColorPurple
|
||||
)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### YAML Configuration
|
||||
|
||||
```yaml
|
||||
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
|
||||
|
||||
```go
|
||||
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:
|
||||
|
||||
```go
|
||||
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
|
||||
Reference in New Issue
Block a user