refactor: merge retry target type into http (max_retries=0 = fire-and-forget)
All checks were successful
check / check (push) Successful in 1m46s
All checks were successful
check / check (push) Successful in 1m46s
This commit is contained in:
48
README.md
48
README.md
@@ -291,20 +291,23 @@ events should be forwarded.
|
||||
| `id` | UUID | Primary key |
|
||||
| `webhook_id` | UUID | Foreign key → Webhook |
|
||||
| `name` | string | Human-readable name |
|
||||
| `type` | TargetType | One of: `http`, `retry`, `database`, `log` |
|
||||
| `type` | TargetType | One of: `http`, `database`, `log` |
|
||||
| `active` | boolean | Whether deliveries are enabled (default: true) |
|
||||
| `config` | JSON text | Type-specific configuration |
|
||||
| `max_retries` | integer | Maximum retry attempts (for retry targets) |
|
||||
| `max_queue_size` | integer | Maximum queued deliveries (for retry targets) |
|
||||
| `max_retries` | integer | Maximum retry attempts for HTTP targets (0 = fire-and-forget, >0 = retries with backoff) |
|
||||
| `max_queue_size` | integer | Maximum queued deliveries (for HTTP targets with retries) |
|
||||
|
||||
**Relations:** Belongs to Webhook. Has many Deliveries.
|
||||
|
||||
**Target types:**
|
||||
|
||||
- **`http`** — Forward the event as an HTTP POST to a configured URL.
|
||||
Fire-and-forget: a single attempt with no retries.
|
||||
- **`retry`** — Forward the event via HTTP POST with automatic retry on
|
||||
failure. Uses exponential backoff up to `max_retries` attempts.
|
||||
Behavior depends on `max_retries`: when `max_retries` is 0 (the
|
||||
default), the target operates in fire-and-forget mode — a single
|
||||
attempt with no retries and no circuit breaker. When `max_retries` is
|
||||
greater than 0, failed deliveries are retried with exponential backoff
|
||||
up to `max_retries` attempts, protected by a per-target circuit
|
||||
breaker.
|
||||
- **`database`** — Confirm the event is stored in the webhook's
|
||||
per-webhook database (no external delivery). Since events are always
|
||||
written to the per-webhook DB on ingestion, this target marks delivery
|
||||
@@ -495,10 +498,12 @@ External Service
|
||||
┌── bounded worker pool (N workers) ──┐
|
||||
▼ ▼ ▼
|
||||
┌────────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ HTTP Target│ │Retry Target│ │ Log Target │
|
||||
│ (1 attempt)│ │ (backoff + │ │ (stdout) │
|
||||
└────────────┘ │ circuit │ └────────────┘
|
||||
│ breaker) │
|
||||
│ HTTP Target│ │ HTTP Target│ │ Log Target │
|
||||
│(max_retries│ │(max_retries│ │ (stdout) │
|
||||
│ == 0) │ │ > 0, │ └────────────┘
|
||||
│ fire+forget│ │ backoff + │
|
||||
└────────────┘ │ circuit │
|
||||
│ breaker) │
|
||||
└────────────┘
|
||||
```
|
||||
|
||||
@@ -553,9 +558,9 @@ This means:
|
||||
durable fallback that ensures no retry is permanently lost, even under
|
||||
extreme backpressure.
|
||||
|
||||
### Circuit Breaker (Retry Targets)
|
||||
### Circuit Breaker (HTTP Targets with Retries)
|
||||
|
||||
Retry targets are protected by a **per-target circuit breaker** that
|
||||
HTTP targets with `max_retries` > 0 are protected by a **per-target circuit breaker** that
|
||||
prevents hammering a down target with repeated failed delivery attempts.
|
||||
The circuit breaker is in-memory only and resets on restart (which is
|
||||
fine — startup recovery rescans the database anyway).
|
||||
@@ -594,9 +599,10 @@ fine — startup recovery rescans the database anyway).
|
||||
- **Failure threshold:** 5 consecutive failures before opening
|
||||
- **Cooldown:** 30 seconds in open state before probing
|
||||
|
||||
**Scope:** Circuit breakers only apply to **retry** target types. HTTP
|
||||
targets (fire-and-forget), database targets (local operations), and log
|
||||
targets (stdout) do not use circuit breakers.
|
||||
**Scope:** Circuit breakers only apply to **HTTP targets with
|
||||
`max_retries` > 0**. Fire-and-forget HTTP targets (`max_retries` == 0),
|
||||
database targets (local operations), and log targets (stdout) do not use
|
||||
circuit breakers.
|
||||
|
||||
When a circuit is open and a new delivery arrives, the engine marks the
|
||||
delivery as `retrying` and schedules a retry timer for after the
|
||||
@@ -704,7 +710,7 @@ webhooker/
|
||||
│ │ └── globals.go # Build-time variables (appname, version, arch)
|
||||
│ ├── delivery/
|
||||
│ │ ├── engine.go # Event-driven delivery engine (channel + timer based)
|
||||
│ │ └── circuit_breaker.go # Per-target circuit breaker for retry targets
|
||||
│ │ └── circuit_breaker.go # Per-target circuit breaker for HTTP targets with retries
|
||||
│ ├── handlers/
|
||||
│ │ ├── handlers.go # Base handler struct, JSON helpers, template rendering
|
||||
│ │ ├── auth.go # Login, logout handlers
|
||||
@@ -838,8 +844,8 @@ linted, tested, and compiled.
|
||||
### Completed: Core Webhook Engine (Phase 2 of MVP)
|
||||
- [x] Implement webhook reception and event storage at `/webhook/{uuid}`
|
||||
- [x] Build event processing and target delivery engine
|
||||
- [x] Implement HTTP target type (fire-and-forget POST)
|
||||
- [x] Implement retry target type (exponential backoff)
|
||||
- [x] Implement HTTP target type (fire-and-forget with max_retries=0,
|
||||
retries with exponential backoff when max_retries>0)
|
||||
- [x] Implement database target type (store events in per-webhook DB)
|
||||
- [x] Implement log target type (console output)
|
||||
- [x] Webhook management pages (list, create, edit, delete)
|
||||
@@ -861,9 +867,9 @@ linted, tested, and compiled.
|
||||
(events are already in the per-webhook DB)
|
||||
- [x] Parallel fan-out: all targets for an event are delivered via
|
||||
the bounded worker pool (no goroutine-per-target)
|
||||
- [x] Circuit breaker for retry targets: tracks consecutive failures
|
||||
per target, opens after 5 failures (30s cooldown), half-open
|
||||
probe to test recovery
|
||||
- [x] Circuit breaker for HTTP targets with retries: tracks consecutive
|
||||
failures per target, opens after 5 failures (30s cooldown),
|
||||
half-open probe to test recovery
|
||||
|
||||
### Remaining: Core Features
|
||||
- [ ] Per-webhook rate limiting in the receiver handler
|
||||
|
||||
Reference in New Issue
Block a user