notifier

package module
v0.0.0-...-242e66e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2026 License: MIT Imports: 12 Imported by: 0

README

notifier

A Go library for sending HTTP notifications with built-in resilience features.

Features

  • Non-blockingNotify() returns immediately after queuing
  • Worker pool — Limits concurrent connections to prevent resource exhaustion
  • Buffered queue — Absorbs traffic spikes without blocking callers
  • Retry with backoff — Automatic retry with exponential backoff and jitter
  • Circuit breaker — Fail fast when the target service is unhealthy
  • Error handling — Callback for handling notification failures

Installation

go get github.com/fibrasek/notifier

Usage

Basic
package main

import (
    "log"
    "github.com/fibrasek/notifier"
)

func main() {
    client, err := notifier.New("https://api.example.com/notify")
    if err != nil {
        log.Fatal(err)
    }

    client.Start()
    defer client.Stop()

    if err := client.Notify("something happened"); err != nil {
        log.Printf("failed to queue: %v", err)
    }
}
With Options
client, err := notifier.New("https://api.example.com/notify",
    notifier.WithWorkers(20),
    notifier.WithQueueSize(500),
    notifier.WithTimeout(10*time.Second),
    notifier.WithContentType("application/json"),
    notifier.WithErrorHandler(func(msg string, err *notifier.NotificationError) {
        log.Printf("notification failed: %s, error: %v", msg, err)
    }),
)
With Retry

Retries failed requests with exponential backoff and jitter:

client, err := notifier.New("https://api.example.com/notify",
    notifier.WithRetry(notifier.RetryConfig{
        MaxRetries: 3,
        BaseDelay:  100 * time.Millisecond,
        MaxDelay:   5 * time.Second,
    }),
)

Only retryable errors (network failures, 5xx responses) are retried. Client errors (4xx) fail immediately.

With Circuit Breaker

Prevents cascading failures by failing fast when the target is unhealthy:

client, err := notifier.New("https://api.example.com/notify",
    notifier.WithCircuitBreaker(notifier.CircuitBreakerConfig{
        FailureThreshold: 5,
        ResetTimeout:     30 * time.Second,
    }),
)

When failures reach the threshold, the circuit opens and requests fail immediately. After the reset timeout, one request is allowed through to test recovery.

Configuration Options

Option Default Description
WithWorkers(n) 10 Number of concurrent workers
WithQueueSize(n) 1000 Message queue capacity
WithTimeout(d) 30s HTTP request timeout
WithContentType(s) text/plain; charset=utf-8 Content-Type header
WithHTTPClient(c) Custom *http.Client
WithErrorHandler(f) Failure callback
WithRetry(cfg) Enable retry with backoff
WithCircuitBreaker(cfg) Enable circuit breaker

Error Handling

Notify() returns immediately with one of:

  • nil — Message queued successfully
  • ErrClientNotStartedStart() not called or client stopped
  • ErrQueueFull — Queue at capacity, apply backpressure

For delivery failures, use WithErrorHandler:

notifier.WithErrorHandler(func(msg string, err *notifier.NotificationError) {
    if err.StatusCode > 0 {
        log.Printf("server rejected: %d", err.StatusCode)
    } else {
        log.Printf("network error: %v", err.Unwrap())
    }

    if err.IsRetryable() {
        // Could re-queue or persist for later
    }
})

License

MIT

Documentation

Overview

Package notifier provides an HTTP notification client that sends messages to a configured endpoint via POST requests.

The Client is designed to handle high-throughput scenarios by using a worker pool to limit concurrent connections and a buffered queue to absorb message spikes. The Client.Notify method is non-blocking, returning immediately after queuing the message.

For fault tolerance, the client supports optional retry with exponential backoff via WithRetry and circuit breaker pattern via WithCircuitBreaker.

Basic usage:

client := notifier.New("https://api.example.com/notify",
	notifier.WithWorkers(20),
	notifier.WithQueueSize(500),
)
client.Start()
defer client.Stop()

err := client.Notify("event occurred")

Index

Constants

View Source
const (
	// DefaultWorkers is the default number of concurrent workers processing notifications.
	DefaultWorkers = 10

	// DefaultQueueSize is the default capacity of the message queue.
	DefaultQueueSize = 1000

	// DefaultTimeout is the default timeout for HTTP requests.
	DefaultTimeout = 30 * time.Second
)

Variables

View Source
var (
	// ErrClientNotStarted indicates [Client.Notify] was called before [Client.Start].
	ErrClientNotStarted = errors.New("client not started")

	// ErrQueueFull indicates the message queue has reached capacity.
	// The caller should retry later or handle backpressure.
	ErrQueueFull = errors.New("notification queue is full")
)

Sentinel errors returned by Client.Notify.

Functions

This section is empty.

Types

type CircuitBreakerConfig

type CircuitBreakerConfig = circuitbreaker.Config

CircuitBreakerConfig configures the circuit breaker. See WithCircuitBreaker for usage.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client sends notifications to an HTTP endpoint.

A Client must be created with New and started with Client.Start before use. Call Client.Stop to gracefully shut down and wait for pending notifications to complete.

A stopped Client cannot be restarted. Create a new Client if needed.

Client is safe for concurrent use by multiple goroutines.

func New

func New(url string, opts ...Option) (*Client, error)

New creates a Client configured to send notifications to the specified URL. Returns an error if the URL is empty or malformed. Options can be provided to customize the client behavior.

func (*Client) Notify

func (c *Client) Notify(message string) error

Notify queues a message for asynchronous delivery.

Notify is non-blocking and returns immediately after queuing the message. The actual HTTP request is performed by a background worker.

Notify returns ErrClientNotStarted if Client.Start has not been called, or ErrQueueFull if the message queue has reached capacity.

func (*Client) Start

func (c *Client) Start()

Start initializes the worker pool and begins processing messages. Start must be called before Client.Notify. Calling Start on an already started client has no effect.

func (*Client) Stop

func (c *Client) Stop()

Stop gracefully shuts down the client. Stop closes the message queue and waits for all pending notifications to complete before returning. After Stop returns, the client cannot be restarted.

Stop is safe to call multiple times; subsequent calls have no effect.

type ErrorHandler

type ErrorHandler func(message string, err *NotificationError)

ErrorHandler is called when a notification fails after all retry attempts. The handler receives the original message content and the error describing what went wrong. ErrorHandler is invoked from a worker goroutine.

type NotificationError

type NotificationError struct {
	// Message is the original notification content that failed to send.
	Message string

	// StatusCode is the HTTP status code, if the server responded.
	// Zero if the request failed before receiving a response.
	StatusCode int

	// Err is the underlying error, if any (e.g., network failure).
	Err error
}

NotificationError describes a failure to send a notification. It contains either a network/transport error in Err, or an HTTP status code indicating the server rejected the request.

func (*NotificationError) Error

func (e *NotificationError) Error() string

Error returns a human-readable description of the notification failure.

func (*NotificationError) IsRetryable

func (e *NotificationError) IsRetryable() bool

IsRetryable reports whether the error is transient and worth retrying. Network errors and server errors (5xx) are retryable. Client errors (4xx) are not retryable.

func (*NotificationError) Unwrap

func (e *NotificationError) Unwrap() error

Unwrap returns the underlying error for use with errors.Is and errors.As.

type Option

type Option func(*Client)

Option configures a Client. Options are passed to New.

func WithCircuitBreaker

func WithCircuitBreaker(config CircuitBreakerConfig) Option

WithCircuitBreaker enables the circuit breaker pattern.

When the failure threshold is reached, the circuit opens and subsequent requests fail immediately with circuitbreaker.ErrOpen. After the reset timeout, one request is allowed through to test recovery. If it succeeds, the circuit closes; if it fails, the circuit reopens.

The circuit breaker is shared across all workers, so failures from concurrent requests accumulate together. With many workers and a low threshold, the circuit may open quickly under sustained failures.

func WithContentType

func WithContentType(contentType string) Option

WithContentType sets the Content-Type header for notification requests. Default is "text/plain; charset=utf-8".

func WithErrorHandler

func WithErrorHandler(handler ErrorHandler) Option

WithErrorHandler sets the callback invoked when a notification fails. The handler is called from a worker goroutine after all retry attempts are exhausted or when a non-retryable error occurs.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) Option

WithHTTPClient sets a custom http.Client for sending requests. Use this to configure custom transport, TLS settings, or connection pooling. Nil values are ignored.

func WithQueueSize

func WithQueueSize(size int) Option

WithQueueSize sets the capacity of the message queue. When the queue is full, Client.Notify returns ErrQueueFull. Values less than 1 are ignored. Default is DefaultQueueSize.

func WithRetry

func WithRetry(config RetryConfig) Option

WithRetry enables automatic retry of failed notifications with exponential backoff and jitter. Only retryable errors (network errors and 5xx responses) are retried; client errors (4xx) fail immediately.

func WithTimeout

func WithTimeout(timeout time.Duration) Option

WithTimeout sets the timeout for HTTP requests. This is only used if a custom http.Client is not provided. Values less than or equal to 0 are ignored. Default is DefaultTimeout.

func WithWorkers

func WithWorkers(n int) Option

WithWorkers sets the number of concurrent workers processing notifications. Workers determine the maximum number of simultaneous HTTP requests. Values less than 1 are ignored. Default is DefaultWorkers.

type RetryConfig

type RetryConfig = retry.Config

RetryConfig configures retry behavior with exponential backoff and jitter. See WithRetry for usage.

Directories

Path Synopsis
internal
circuitbreaker
Package circuitbreaker implements the circuit breaker pattern for fault tolerance.
Package circuitbreaker implements the circuit breaker pattern for fault tolerance.
retry
Package retry provides retry logic with exponential backoff and jitter.
Package retry provides retry logic with exponential backoff and jitter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL