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
147 changes: 113 additions & 34 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,128 @@ name: CI

on:
push:
branches:
- main
- '**'
pull_request:
branches: [ main ]
branches: [ '*' ]

jobs:
tests:
name: Run tests (Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }})
compile:
name: Compile
runs-on: ubuntu-latest

strategy:
matrix:
include:
- os: ubuntu-latest
elixir: 1.18
otp: 27
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Install dependencies
run: mix deps.get

- name: Compile with warnings as errors
run: mix compile --warnings-as-errors

format:
name: Format Check
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'

runs-on: ${{ matrix.os }}
env:
MIX_ENV: test
- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Install dependencies
run: mix deps.get

- name: Check code formatting
run: mix format --check-formatted

credo:
name: Credo
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}
- name: Install dependencies
run: mix deps.get

- name: Run Credo strict
run: mix credo --strict

dialyzer:
name: Dialyzer
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
mix deps.get
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'

- name: Check source code format
run: mix format --check-formatted
- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Remove compiled application files
run: mix clean
- name: Install dependencies
run: mix deps.get

- name: Compile & lint dependencies
run: mix compile --warnings-as-errors
- name: Restore Dialyzer PLT cache
uses: actions/cache@v4
with:
path: priv/plts
key: ${{ runner.os }}-dialyzer-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-dialyzer-

- name: Run tests
run: mix test
- name: Run Dialyzer
run: mix dialyzer --halt-exit-status
49 changes: 49 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Test

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]

jobs:
test:
name: Test
runs-on: ubuntu-latest

services:
mailhog:
image: mailhog/mailhog:latest
ports:
- 1025:1025
- 8025:8025

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: '1.18'
otp-version: '28'

- uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: |
deps
_build
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: |
${{ runner.os }}-mix-

- name: Install dependencies
run: mix deps.get

- name: Run tests
run: mix test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ abyss-*.tar
.devenv/
.devenv.*

priv/plts/
96 changes: 96 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **New configuration options for enhanced control**:
- `connection_telemetry_sample_rate` (default: 0.05) - Configure sampling rate for connection telemetry events
- `handler_memory_check_interval` (default: 10_000ms) - Interval for handler memory monitoring
- `handler_memory_warning_threshold` (default: 100 MB) - Memory threshold for warnings
- `handler_memory_hard_limit` (default: 150 MB) - Hard memory limit triggering termination

- **Modular UDP transport architecture**:
- `Abyss.Transport.UDP.Core` - Core UDP socket operations
- `Abyss.Transport.UDP.Unicast` - Unicast-specific functionality
- `Abyss.Transport.UDP.Broadcast` - Broadcast-specific functionality

- **Enhanced telemetry metrics**:
- Rolling window rate calculations for accepts_per_second and responses_per_second
- Atomic ETS operations for concurrent metric updates
- Response time tracking with per-request measurements

### Changed

- **Improved listener scaling algorithm**: Changed `calculate_optimal_listeners/2` to use 1:100 ratio (1 listener per 100 connections) instead of 1:1000, providing better granularity for low to medium loads
- **Adaptive timeout calculation**: Now consistently uses milliseconds throughout, improving accuracy and preventing time unit bugs
- **Telemetry sampling**: Connection telemetry events now respect configurable sampling rate from ServerConfig

### Fixed

- **Critical ETS race condition**: Fixed race condition in telemetry metrics table creation when multiple processes initialize simultaneously using try/catch pattern
- **Time unit inconsistency**: Fixed adaptive timeout calculation that was incorrectly mixing native time units with milliseconds in bounds checking
- **Socket leak**: Fixed resource leak in `Abyss.Transport.UDP.Unicast.send_recv/3` by ensuring socket cleanup in all code paths
- **Telemetry rate calculation**: Improved rolling window rate calculations with proper atomic operations and window expiration handling
- **Configuration validation**: Added comprehensive validation for all new configuration options with clear error messages

### Improved

- **Test coverage**: Increased from ~40% to 62%+ coverage
- **Test cleanup**: Removed 5 skipped/placeholder tests for a cleaner test suite (237 tests, 0 failures, 0 skipped)
- **Code quality**: Addressed all critical and medium priority code quality issues
- **Documentation**: Updated CLAUDE.md with comprehensive development guidelines
- **Memory management**: Configurable memory monitoring with graceful degradation

### Technical Details

#### Telemetry Improvements

The telemetry system now uses atomic ETS operations to prevent race conditions:

```elixir
# Before: Non-atomic read-modify-write
count = :ets.lookup_element(table, :accepts_in_window, 2)
:ets.insert(table, {:accepts_in_window, count + 1})

# After: Atomic increment
:ets.update_counter(table, :accepts_in_window, {2, 1})
```

#### Adaptive Timeout Fix

Fixed time unit handling in adaptive timeout calculations:

```elixir
# Before: Mixing native and millisecond units
avg_time_native = Enum.sum(times) / length(times)
timeout = round(avg_time_native * 3)
timeout |> max(div(base_timeout, 2)) |> min(base_timeout * 2)

# After: Consistent millisecond units
avg_time_native = Enum.sum(times) / length(times)
avg_time_ms = System.convert_time_unit(round(avg_time_native), :native, :millisecond)
timeout_ms = round(avg_time_ms * 3)
timeout_ms |> max(div(base_timeout, 2)) |> min(base_timeout * 2)
```

#### Listener Scaling Enhancement

Improved scaling granularity for better performance under varying loads:

```elixir
# Before: 1 listener per 1000 connections
base_listeners = max(div(current_connections, 1000), 1)

# After: 1 listener per 100 connections
base_listeners = max(div(current_connections, 100), 1)
```

## [0.4.0] - Previous Release

Initial stable release with core UDP server functionality, telemetry support, and security features.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ Starts an Abyss server with the given options.
- `rate_limit_window_ms` - Rate limit window in ms (default: 1000)
- `max_packet_size` - Maximum packet size in bytes (default: 8192)
- `broadcast` - Enable broadcast mode (default: false)
- `connection_telemetry_sample_rate` - Sampling rate for connection telemetry (default: 0.05)
- `handler_memory_check_interval` - Memory check interval in ms (default: 10_000)
- `handler_memory_warning_threshold` - Memory warning threshold in MB (default: 100)
- `handler_memory_hard_limit` - Memory hard limit in MB (default: 150)

#### `stop/2`

Expand Down Expand Up @@ -432,6 +436,16 @@ Abyss (main supervisor)
4. **Handler**: Processes packet data using user-defined logic
5. **Transport**: Handles low-level UDP socket operations

### Transport Layer

Abyss uses a modular transport architecture with specialized modules:

- **`Abyss.Transport.UDP.Core`** - Core UDP socket operations (open, close, send, recv)
- **`Abyss.Transport.UDP.Unicast`** - Unicast-specific functionality with proper resource cleanup
- **`Abyss.Transport.UDP.Broadcast`** - Broadcast and multicast support

This modular design ensures proper resource management and makes it easier to extend or customize transport behavior.

### Supervision Strategy

- **Rest for One**: If a listener crashes, other listeners continue
Expand Down Expand Up @@ -474,4 +488,3 @@ mix docs
## License

This project is licensed under the MIT License - see the LICENSE file for details.
# Updated at Wed Oct 15 13:02:51 CST 2025
Loading