MCPcopy Index your code
hub / github.com/aaydin-tr/divisor

github.com/aaydin-tr/divisor @v0.6.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.6.0 ↗ · + Follow
246 symbols 869 edges 35 files 6 documented · 2% updated 6mo agov0.6.0 · 2025-12-16★ 746 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Divisor

A fast and easy-to-configure load balancer

Table of Contents

  1. About The Project
  2. Features
  3. Installation
  4. Usage
  5. Configuration
  6. Custom Middleware
  7. Limitations
  8. Benchmark
  9. TODO
  10. Contributors
  11. License

About The Project

This project is designed to provide a fast and easy-to-configure load balancer in Go language. It currently includes round-robin, weighted round-robin, least-connection, least-response-time, ip-hash and random algorithms, but we have more to add to our TODO list.

The project is developed using the fasthttp library for HTTP/1.1, which ensures high performance. For HTTP/2 support, it uses the native Go net/http package with HTTP/2 configuration. Its purpose is to distribute the load evenly among multiple servers by routing incoming requests.

The project aims to simplify the configuration process for users while performing the essential functions of load balancers. Therefore, it offers several configuration options that can be adjusted to meet the users needs.

This project is particularly suitable for large-scale applications and websites. It can be used for any application that requires a load balancer, thanks to its high performance, ease of configuration, and support for different algorithms.

Features

  • Fast and easy-to-configure load balancer.
  • Supports round-robin, weighted round-robin, least-connection, least-response-time, IP hash, and random algorithms.
  • Supports TLS and HTTP/2 for the frontend server.
  • Support for custom middleware written in Go.
  • Uses the fasthttp library for HTTP/1.1 and native Go net/http package for HTTP/2, ensuring high performance and scalability.
  • Offers multiple configuration options to suit user needs.
  • Can handle large-scale applications and websites.
  • Includes a built-in monitoring system that displays real-time information on the system's CPU usage, RAM usage, number of Goroutines, and open connections.
  • Prometheus support for monitoring. (http://monitoring-host:monitoring-port/metrics can be used to get prometheus metrics)
  • Provides information on each server's average response time, total request count, and last time used.
  • Lightweight and efficient implementation for minimal resource usage.

Installation

Downloading the Release

The latest release of Divisor can be downloaded from the releases page. Choose the suitable binary for your system, download and extract the archive, and then move the binary to a directory in your system's $PATH variable (e.g. /usr/local/bin).

Building from Source

Alternatively, you can build Divisor from source by cloning this repository to your local machine and running the following commands:

git clone https://github.com/aaydin-tr/divisor.git &&
cd divisor &&
go build -o divisor &&
./divisor

Using go install

You can also install Divisor using the go install command:

go install github.com/aaydin-tr/divisor@latest

This will install the divisor binary to your system's $GOPATH/bin directory. Make sure this directory is included in your system's $PATH variable to make the divisor accessible from anywhere.

That's it! You're now ready to use Divisor in your project.

Usage

You need a config.yaml file to use Divisor, you can give this file to Divisor to use with the --config flag, by default it will try to use a config.yaml file in the directory it is in. Example config files

:warning: Please use absolute path for "config.yaml" while using "--config" flag

Configuration

Minimal Example

port: 8000  # Required
backends:
  - url: localhost:8080
  - url: localhost:7070

Core Settings

Name Description Type Default Required
port Server port string - ⚠️ Yes
host Server host string localhost No
type Load balancing algorithm string round-robin No
health_checker_time Health check interval for backends duration 30s No

Valid algorithm types: round-robin, w-round-robin, ip-hash, random, least-connection, least-response-time

Backend Settings

Name Description Type Default Required
backends List of backend servers array - ⚠️ Yes (min: 1)
backends.url Backend URL (without protocol) string - ⚠️ Yes
backends.health_check_path Health check endpoint string / No
backends.weight Backend weight (w-round-robin only) int - ⚠️ w-round-robin
backends.max_conn Max connections per backend int 512 No
backends.max_conn_timeout Max wait time for free connection duration 30s No
backends.max_conn_duration Connection keep-alive duration duration 10s No
backends.max_idle_conn_duration Idle connection timeout duration 10s No
backends.max_idemponent_call_attempts Retry attempts for idempotent calls int 5 No

Monitoring Settings

Name Description Type Default
monitoring.host Metrics server host string localhost
monitoring.port Metrics server port string 8001

Server Settings

Name Description Type Default
server.http_version HTTP protocol version (http1 or http2) string http1
server.cert_file TLS certificate file path string -
server.key_file TLS private key file path string -
server.max_idle_worker_duration Worker pool idle timeout duration 10s
server.tcp_keepalive_period TCP keep-alive interval (OS default if unset) duration -
server.concurrency Max concurrent connections int 262144
server.read_timeout Request read timeout duration unlimited
server.write_timeout Response write timeout duration unlimited
server.idle_timeout Keep-alive idle timeout duration unlimited
server.disable_keepalive Force connection close after response bool false
server.disable_header_names_normalizing Preserve original header name casing bool false

Custom Headers

Name Description Type
custom_headers Headers injected into backend requests map
custom_headers.<name> Header value (special variables supported) string

Special variables: $remote_addr (client IP), $time (request timestamp), $uuid (request UUID), $incremental (per-backend counter)

Example:

custom_headers:
  x-client-ip: $remote_addr
  x-request-id: $uuid

Middlewares

Name Description Type Default Required
middlewares List of custom middleware array - No
middlewares.name Middleware identifier string - ⚠️ Yes
middlewares.disabled Skip middleware execution bool false No
middlewares.code Inline Go code string - ⚠️ Yes (or file)
middlewares.file Path to Go code file string - ⚠️ Yes (or code)
middlewares.config Config passed to middleware constructor map - No

Important Notes

  • Protocol stripping: Backend URLs automatically have http:// or https:// removed
  • HTTP/2 requirement: server.http_version: http2 requires both cert_file and key_file
  • Weighted round-robin: Single backend auto-converts to regular round-robin
  • Middleware validation: Must specify either code OR file (not both), unless disabled: true
  • Custom header validation: Only accepts the 4 special variables listed above
  • Default algorithm: If type is omitted or invalid, defaults to round-robin

Please see example config files

Custom Middleware

Divisor supports custom middleware written in Go. You can define middleware to intercept requests and responses, allowing you to implement custom logic such as authentication, logging, header manipulation, etc.

The middleware is executed using the Yaegi interpreter.

Usage

Your middleware must implement the Middleware interface and provide a New function constructor.

:warning: Make sure you run go get github.com/aaydin-tr/divisor/middleware to import the middleware package.

package middleware

import (
    "github.com/aaydin-tr/divisor/middleware"
    "fmt"
)

type MyMiddleware struct {
    config map[string]any
}

func New(config map[string]any) middleware.Middleware {
    return &MyMiddleware{config: config}
}

func (m *MyMiddleware) OnRequest(ctx *middleware.Context) error {
    // Logic to execute before request reached to backend server
    // e.g. ctx.Request.Header.Set("X-Custom-Header", "Value")
    fmt.Println("OnRequest")
    return nil
}

func (m *MyMiddleware) OnResponse(ctx *middleware.Context, err error) error {
    // Logic to execute after response is received from backend server
    fmt.Println("OnResponse")
    return nil
}

Configuration

You can configure middlewares in config.yaml using either inline code or a file path.

Using a file:

middlewares:
  - name: "my-logger"
    file: "./middleware/logger.go"
    config:
      prefix: "[LOG]"

Using inline code:

middlewares:
  - name: "simple-header"
    code: |
      package middleware

      import "github.com/aaydin-tr/divisor/middleware"

      type HeaderMiddleware struct {}

      func New(config map[string]any) middleware.Middleware {
          return &HeaderMiddleware{}
      }

      func (h *HeaderMiddleware) OnRequest(ctx *middleware.Context) error {
          ctx.Request.Header.Set("X-Divisor", "True")
          return nil
      }

      func (h *HeaderMiddleware) OnResponse(ctx *middleware.Context, err error) error {
          return nil
      }

Request/Response Lifecycle

The middleware execution flow allows you to intercept and control the complete request/response lifecycle. Here's exactly what happens when a request is processed:

Complete Request Flow

  1. Pre-Request Setup

    • Internal request preprocessing occurs
    • Headers and request context are prepared
  2. OnRequest Middleware Execution

    • Executed before the request is sent to the backend
    • Receives the middleware context with full access to request/response
    • If OnRequest returns an error:
      • ⛔ The execution chain stops immediately
      • ⛔ The request is NOT sent to the backend
      • OnResponse is NOT called
      • ⛔ Post-response cleanup occurs
      • ⛔ The error is returned to the client
    • If OnRequest succeeds (returns nil):
      • ✅ Execution continues to backend proxy
  3. Backend Proxy

    • The request is forwarded to the selected backend server
    • The response (or error) is captured and stored
    • Important: Even if the backend fails, execution continues to OnResponse
  4. OnResponse Middleware Execution

    • Always executed after the proxy attempt (success or failure)
    • Receives two arguments:
      1. The middleware context
      2. The backend error (if any) - will be nil on success
    • You can inspect the backend error and decide how to handle it
    • If OnResponse returns an error:
      • ⚠️ It overrides any backend error
      • ⚠️ Post-response cleanup occurs
      • ⚠️ This error is returned to the client
      • ⚠️ The standard error response is replaced
    • If OnResponse returns nil:
      • Execution continues normally
      • If backend error exists, standard 500 error response is generated
      • If no error, the backend response is sent to client
  5. Post-Response Cleanup

    • Internal response postprocessing occurs
    • Always executed regardless of success or failure
  6. Response Sent

    • Final response is sent to the client

Key Takeaways

  • 🎯 OnRequest acts as a gatekeeper - it can block requests before they reach the backend
  • 🔄 OnResponse always runs after the proxy attempt, giving you a chance to handle backend errors
  • 🛡️ OnResponse can override backend errors, allowing custom error handling and responses
  • ⏱️ Both middlewares have access to the full request/response context for inspection and modification

Request/Response Diagram

```mermaid flowchart TD Start([Client Request]) --> PreReq[Pre-Request Setup] PreReq --> OnReq{OnRequest Middleware}

OnReq -->|Returns Error| PostRes1[Post-Response Cleanup]
PostRes1 --> ReturnErr([Return OnRequest Error])

OnReq -->|Returns nil| Proxy[Forward to Backend Server]

Proxy --> CaptureErr[Capture Backend Response/Error]
CaptureErr --> OnRes{OnResponse Middleware}

OnRes -->|R

Extension points exported contracts — how you extend this code

IBalancer (Interface)
(no doc) [5 implementers]
core/types/type.go
Middleware (Interface)
(no doc) [2 implementers]
middleware/middleware.go
IProxyClient (Interface)
(no doc) [2 implementers]
internal/proxy/proxy.go
IsHostAlive (FuncType)
(no doc)
core/types/type.go
New (FuncType)
(no doc)
middleware/middleware.go
ProxyFunc (FuncType)
(no doc)
internal/proxy/proxy.go
HashFunc (FuncType)
(no doc)
core/types/type.go

Core symbols most depended-on inside this repo

ReverseProxyHandler
called by 44
internal/proxy/proxy.go
NewExecutor
called by 29
pkg/middleware/executor.go
Close
called by 23
internal/proxy/proxy.go
NewLeastAlgorithm
called by 16
core/least-algorithm/least-algorithm.go
Shutdown
called by 15
core/types/type.go
S2B
called by 15
pkg/helper/helper.go
Stat
called by 13
internal/proxy/proxy.go
NewRoundRobin
called by 12
core/round-robin/round-robin.go

Shape

Function 124
Method 81
Struct 33
FuncType 4
Interface 3
TypeAlias 1

Languages

Go100%

Modules by API surface

internal/proxy/proxy_test.go20 symbols
internal/proxy/proxy.go18 symbols
pkg/config/config.go14 symbols
pkg/helper/helper.go11 symbols
pkg/consistent/consistent.go10 symbols
core/least-algorithm/least-algorithm_test.go10 symbols
core/least-algorithm/least-algorithm.go10 symbols
core/w-round-robin/w-round-robin_test.go9 symbols
core/w-round-robin/w-round-robin.go9 symbols
core/round-robin/round-robin_test.go9 symbols
core/round-robin/round-robin.go9 symbols
core/random/random_test.go9 symbols

For agents

$ claude mcp add divisor \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page