Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions docs/advanced-guide/circuit-breaker/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,42 @@ The circuit breaker tracks consecutive failed requests for a downstream service.



- **Interval:** Once the circuit is open, GoFr starts a background goroutine that periodically checks the health of the service by making requests to its aliveness endpoint (by default: /.well-known/alive) at the specified interval. When the service is deemed healthy again, the circuit breaker closes, allowing requests to resume.
- **Interval:** Once the circuit is open, GoFr starts a background goroutine that periodically checks the health of the service by making requests to its aliveness endpoint (by default: `/.well-known/alive`) at the specified interval. When the service is deemed healthy again, the circuit breaker transitions directly from **Open** to **Closed**, allowing requests to resume.

> GoFr's circuit breaker implementation does not use a **Half-Open** state. Instead, it relies on periodic asynchronous health checks to determine service recovery.

## Failure Conditions

> NOTE: Retries only occur when the target service responds with a 500 Internal Server Error. Errors like 400 Bad Request or 404 Not Found are considered non-transient and will not trigger retries.
The Circuit Breaker counts a request as "failed" if:
1. An error occurs during the HTTP request (e.g., network timeout, connection refused).
2. The response status code is **greater than 500** (e.g., 502, 503, 504).

> **Note:** HTTP 500 Internal Server Error is **NOT** counted as a failure for the circuit breaker. This distinguishes between application bugs (500) and service availability issues (> 500).

## Health Check Requirement

For the Circuit Breaker to recover from an **Open** state, the downstream service **must** expose a health check endpoint that returns a `200 OK` status code.

- **Default Endpoint:** `/.well-known/alive`
- **Custom Endpoint:** Can be configured using `service.HealthConfig`.

> [!WARNING]
> If the downstream service does not have a valid health check endpoint (returns 404 or other errors), the Circuit Breaker will **never recover** and will remain permanently Open. Ensure your services implement the health endpoint correctly.

## Interaction with Retry

When using both Retry and Circuit Breaker patterns, the **order of wrapping** is critical for effective resilience:

- **Recommended: Retry as the Outer Layer**
In this configuration, the `Retry` layer wraps the `Circuit Breaker`. Every single retry attempt is tracked by the circuit breaker. If a request retries 5 times, the circuit breaker sees 5 failures. This allows the circuit to trip quickly during a "retry storm," protecting the downstream service from excessive load.

- **Non-Recommended: Circuit Breaker as the Outer Layer**
If the `Circuit Breaker` wraps the `Retry` layer, it only sees the **final result** of the entire retry loop. Even if a request retries 10 times internally, the circuit breaker only counts it as **1 failure**. This delays the circuit's reaction and can lead to hundreds of futile calls hitting a failing service before the breaker finally trips.

> [!IMPORTANT]
> Always ensure `Retry` is the outer layer by providing the `CircuitBreakerConfig` **before** the `RetryConfig` in the `AddHTTPService` options.

> NOTE: Retries only occur when the target service responds with a status code > 500 (e.g., 502 Bad Gateway, 503 Service Unavailable). 500 Internal Server Error and client errors (4xx) are considered non-transient or bug-related and will not trigger retries.
## Usage

```go
Expand Down Expand Up @@ -56,4 +87,8 @@ func main() {
Circuit breaker state changes to open when number of consecutive failed requests increases the threshold.
When it is in open state, GoFr makes request to the aliveness endpoint (default being - /.well-known/alive) at an equal interval of time provided in config.

GoFr publishes the following metric to track circuit breaker state:

- `app_http_circuit_breaker_state`: Current state of the circuit breaker (0 for Closed, 1 for Open). This metric is used to visualize a historical timeline of circuit transitions on the dashboard.

> ##### Check out the example of an inter-service HTTP communication along with circuit-breaker in GoFr: [Visit GitHub](https://github.com/gofr-dev/gofr/blob/main/examples/using-http-service/main.go)
13 changes: 11 additions & 2 deletions docs/advanced-guide/http-communication/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ echo -n "your-password" | base64
- **CircuitBreakerConfig** - This option allows the user to configure the GoFr Circuit Breaker's `threshold` and `interval` for the failing downstream HTTP Service calls. If the failing calls exceeds the threshold the circuit breaker will automatically be enabled.
- **DefaultHeaders** - This option allows user to set some default headers that will be propagated to the downstream HTTP Service every time it is being called.
- **HealthConfig** - This option allows user to add the `HealthEndpoint` along with `Timeout` to enable and perform the timely health checks for downstream HTTP Service.
- **RetryConfig** - This option allows user to add the maximum number of retry count if before returning error if any downstream HTTP Service fails.
- **RetryConfig** - This option allows user to add the maximum number of retry count before returning error if any downstream HTTP Service fails. Retries are triggered for network errors and status codes **> 500** (e.g., 503 Service Unavailable). HTTP 500 is not retried.
- **RateLimiterConfig** - This option allows user to configure rate limiting for downstream service calls using token bucket algorithm. It controls the request rate to prevent overwhelming dependent services and supports both in-memory and Redis-based implementations.

**Rate Limiter Store: Customization**
Expand Down Expand Up @@ -226,4 +226,13 @@ a.AddHTTPService("cat-facts", "https://catfact.ninja",
**Best Practices:**
- For distributed systems: It is strongly recommended to use Redis-based store (`NewRedisRateLimiterStore`) to ensure consistent rate limiting across multiple instances of your application.
- For single-instance applications: The default in-memory store (`NewLocalRateLimiterStore`) is sufficient and provides better performance.
- Rate configuration: Set Burst higher than Requests to allow short traffic bursts while maintaining average rate limits.
- Rate configuration: Set Burst higher than Requests to allow short traffic bursts while maintaining average rate limits.

## Metrics

GoFr publishes the following metrics for HTTP service communication:

- `app_http_retry_count`: Total number of retry events. (labels: `service`)
- `app_http_circuit_breaker_state`: Current state of the circuit breaker (0 for Closed, 1 for Open). (labels: `service`)
- `app_http_service_response`: Response time of HTTP service requests in seconds (histogram). (labels: `service`, `path`, `method`, `status`)
```
79 changes: 79 additions & 0 deletions docs/discord-notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Discord Release Notifications

This document describes the automated Discord notification system for GoFr releases.

## Overview

GoFr automatically posts release announcements to Discord when a new version is published on GitHub. The system uses a custom Go tool that handles message splitting, Markdown preservation, and retry logic.

## Features

- **UTF-8 Safe**: Correctly handles emojis and multi-byte Unicode characters
- **Markdown Preservation**: Intelligently splits messages while preserving code block formatting
- **Custom Format**: Posts with `# [🌟 GoFr {version} Released! 🌟](link)` heading
- **@everyone Mention**: Notifies all Discord members
- **Retry Logic**: Automatically retries failed posts (3 attempts)
- **Discord Limit Handling**: Splits messages >2000 characters across multiple posts

## Setup

### 1. Create Discord Webhook

1. Go to your Discord server → Server Settings → Integrations → Webhooks
2. Click "New Webhook"
3. Configure the webhook:
- Name: `GoFr Releases`
- Channel: Select your releases channel
4. Copy the webhook URL

### 2. Add GitHub Secret

1. Go to GitHub repository → Settings → Secrets and variables → Actions
2. Click "New repository secret"
3. Add:
- **Name**: `DISCORD_WEBHOOK`
- **Value**: Your webhook URL from step 1

## How It Works

The workflow is triggered automatically when a release is published:

1. GitHub Actions workflow starts (`.github/workflows/discord-release-notification.yml`)
2. Go tool reads release data from environment variables
3. Constructs formatted message with header and release body
4. Splits message if needed (respecting Markdown and 2000 char limit)
5. Posts to Discord with retry logic

## Message Format

```
@everyone

# [🌟 GoFr v1.26.0 Released! 🌟](https://github.com/gofr-dev/gofr/releases/tag/v1.26.0)

# **Release v1.50.2**

## 🚀 Enhancements
...
```

## Testing

To test the workflow:

1. Create a test release on GitHub
2. Check your Discord channel for the notification
3. Verify formatting and links are correct

## Future Enhancements

- LinkedIn integration for professional visibility
- X (Twitter) integration for thread-based announcements
- Support for additional platforms (Slack, Telegram)

## Technical Details

- **Implementation**: `.github/workflows/scripts/discord_notifier.go`
- **Tests**: `.github/workflows/scripts/discord_notifier_test.go`
- **Test Coverage**: 55.2%
- **Language**: Go (for reliability and Unicode support)
8 changes: 5 additions & 3 deletions docs/navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ export const navigation = [
links: [
{
title: 'Hello Server',
href: '/docs/quick-start/introduction' ,
desc: "Getting started with how to write a server using GoFR with basic examples and explanations. Boost your productivity with efficient coding practices and learn to build scalable applications quickly."},

href: '/docs/quick-start/introduction',
desc: "Getting started with how to write a server using GoFR with basic examples and explanations. Boost your productivity with efficient coding practices and learn to build scalable applications quickly."
},

{
title: 'Configuration',
href: '/docs/quick-start/configuration',
Expand Down Expand Up @@ -273,6 +274,7 @@ export const navigation = [
href: '/docs/references/testing',
desc: "GoFr provides a centralized collection of mocks to facilitate writing effective unit tests. Explore testing strategies and tools for GoFr applications, ensuring the code is robust, reliable, and maintainable."
},

{
title: 'GoFr CLI',
href: '/docs/references/gofrcli',
Expand Down
17 changes: 16 additions & 1 deletion docs/quick-start/observability/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ They are instrumental in measuring and meeting service-level agreements (SLAs) t

GoFr publishes metrics to port: _2121_ on _/metrics_ endpoint in Prometheus format.

### Default Metrics

{% table %}

- Name
Expand Down Expand Up @@ -83,6 +85,7 @@ GoFr publishes metrics to port: _2121_ on _/metrics_ endpoint in Prometheus form
- histogram
- Response time of HTTP service requests in seconds


---

- app_sql_open_connections
Expand Down Expand Up @@ -131,6 +134,18 @@ GoFr publishes metrics to port: _2121_ on _/metrics_ endpoint in Prometheus form
- counter
- Number of successful subscribe operations

---

- app_http_retry_count
- counter
- Total number of retry events

---

- app_http_circuit_breaker_state
- gauge
- Current state of the circuit breaker (0 for Closed, 1 for Open). Used for historical timeline visualization.

{% /table %}

For example: When running the application locally, we can access the /metrics endpoint on port 2121 from: {% new-tab-link title="http://localhost:2121/metrics" href="http://localhost:2121/metrics" /%}
Expand All @@ -150,7 +165,7 @@ METRICS_PORT=0
These metrics can be easily consumed by monitoring systems like {% new-tab-link title="Prometheus" href="https://prometheus.io/" /%}
and visualized in dashboards using tools like {% new-tab-link title="Grafana" href="https://grafana.com/" /%}.

Here's a sample Grafana dashboard utilizing GoFr's metrics:
You can find the dashboard source in the {% new-tab-link title="GoFr repository" href="https://github.com/gofr-dev/gofr/tree/main/examples/http-server/docker/provisioning/dashboards/gofr-dashboard" /%}.

{% figure src="/metrics-dashboard.png" alt="Grafana Dashboard showing GoFr metrics including HTTP request rates,
response times, etc." caption="Example monitoring dashboard using GoFr's built-in metrics" /%}
Expand Down
Loading
Loading