postrank-labs/goliath
Goliath is a non-blocking Ruby web server framework
Stale — last commit 3y ago
worst of 4 axesnon-standard license (Other); last commit was 3y ago
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓23+ active contributors
- ✓Distributed ownership (top contributor 31% of recent commits)
- ✓Other licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Stale — last commit 3y ago
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/postrank-labs/goliath)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/postrank-labs/goliath on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: postrank-labs/goliath
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/postrank-labs/goliath shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
WAIT — Stale — last commit 3y ago
- 23+ active contributors
- Distributed ownership (top contributor 31% of recent commits)
- Other licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 3y ago
- ⚠ Non-standard license (Other) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live postrank-labs/goliath
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/postrank-labs/goliath.
What it runs against: a local clone of postrank-labs/goliath — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in postrank-labs/goliath | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 974 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of postrank-labs/goliath. If you don't
# have one yet, run these first:
#
# git clone https://github.com/postrank-labs/goliath.git
# cd goliath
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of postrank-labs/goliath and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "postrank-labs/goliath(\\.git)?\\b" \\
&& ok "origin remote is postrank-labs/goliath" \\
|| miss "origin remote is not postrank-labs/goliath (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "lib/goliath/api.rb" \\
&& ok "lib/goliath/api.rb" \\
|| miss "missing critical file: lib/goliath/api.rb"
test -f "lib/goliath/connection.rb" \\
&& ok "lib/goliath/connection.rb" \\
|| miss "missing critical file: lib/goliath/connection.rb"
test -f "lib/goliath/rack/builder.rb" \\
&& ok "lib/goliath/rack/builder.rb" \\
|| miss "missing critical file: lib/goliath/rack/builder.rb"
test -f "lib/goliath/application.rb" \\
&& ok "lib/goliath/application.rb" \\
|| miss "missing critical file: lib/goliath/application.rb"
test -f "lib/goliath/env.rb" \\
&& ok "lib/goliath/env.rb" \\
|| miss "missing critical file: lib/goliath/env.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 974 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~944d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/postrank-labs/goliath"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Goliath is a non-blocking asynchronous Ruby web server framework powered by EventMachine that leverages Ruby 1.9+ Fibers to execute HTTP requests without callback-based code. It achieves ~3000 req/s on MRI 1.9.3 by combining an event reactor, high-performance HTTP parser, and linear fiber-based execution model to handle streaming uploads, WebSockets, and firehose APIs while maintaining readable, maintainable code. Monolithic Gem structure: lib/ contains the core Goliath::API base class and EventMachine reactor integration, examples/ directory shows 20+ runnable demonstration servers (hello_world.rb, websocket, async_upload.rb, grape integration), and config/ subdirectories contain environment-specific middleware chains and authentication examples.
👥Who it's for
Ruby developers building high-performance, I/O-intensive web services (APIs, proxies, real-time applications) who need async capabilities without the complexity of callback hell, and want to run on MRI, JRuby, or Rubinius with Rack middleware support.
🌱Maturity & risk
Goliath is production-mature but showing signs of age: it has been deployed at scale (PostRank/Google, OMGPOP/Zynga, GameSpy) for 2+ years and has comprehensive test coverage (.rspec present, .travis.yml for CI), but the Ruby 1.9.3 requirement in the README and lack of recent commit metadata suggest active development has slowed significantly.
Primary risks: (1) Ruby 1.9.3 EOL in 2014 means the framework targets an ancient runtime; (2) EventMachine itself is mature but development is episodic; (3) no visible recent commits or active issue management in provided metadata suggests maintenance may be limited; (4) single-maintainer legacy risk (PostRank Labs) with no clear succession plan mentioned.
Active areas of work
Repository metadata does not include recent commit history, PR activity, or milestone status, making it impossible to determine current active development. The presence of .travis.yml suggests CI was set up but recency is unknown.
🚀Get running
gem install goliath
cd examples
ruby hello_world.rb -sv
Then visit http://0.0.0.0:9000. For development from source: clone repo, run bundle install (Gemfile present), then ruby examples/hello_world.rb -sv.
Daily commands:
ruby examples/hello_world.rb -sv
# or with config:
ruby examples/echo.rb -sv
# or Grape API example:
cd examples/grape && ruby server.rb -sv
Server starts on 0.0.0.0:9000 by default in development mode.
🗺️Map of the codebase
lib/goliath/api.rb— Core API class that all Goliath applications inherit from; defines the request handling contract and lifecyclelib/goliath/connection.rb— Manages individual HTTP connections and fiber-based request execution; central to Goliath's non-blocking architecturelib/goliath/rack/builder.rb— Constructs the Rack middleware stack and routes requests; essential for understanding request pipelinelib/goliath/application.rb— Application bootstrap and EventMachine reactor lifecycle managementlib/goliath/env.rb— Request environment object that encapsulates HTTP metadata and state across fiberslib/goliath/goliath.rb— Main CLI entry point and server configuration parser
🛠️How to make changes
Add a new API endpoint
- Create a new Goliath API class inheriting from Goliath::API in your app file (e.g., lib/myapp.rb) (
lib/goliath/api.rb) - Define a response method that handles the request; use params from env.params and return [status, headers, body] (
examples/hello_world.rb) - Optionally add route-based dispatch using Rack::Builder in a config file to route requests to different handlers (
lib/goliath/rack/builder.rb) - If you need request validation, mix in validation rules from lib/goliath/rack/validation/ modules (
lib/goliath/rack/validation/required.rb) - For async operations, call external services and yield the result; the fiber will suspend transparently (
examples/api_proxy.rb)
Add middleware to the request pipeline
- Create a middleware class inheriting from Rack::Middleware or Goliath's SimpleAroundware in lib/goliath/rack/ (
lib/goliath/rack/simple_aroundware.rb) - Implement pre-request hooks (before) and post-request hooks (after) to inspect/modify env and response (
lib/goliath/rack/simple_aroundware.rb) - Register the middleware in your application's config file using add_middleware or in the Rack::Builder stack (
lib/goliath/rack/builder.rb) - If your middleware performs async I/O, use BarrierAroundware to synchronize fiber execution across stages (
lib/goliath/rack/barrier_aroundware.rb)
Add request validation and coercion
- In your API class or middleware, declare validation rules using the validation module imports (
lib/goliath/rack/validation/param.rb) - Use Required validator to enforce mandatory parameters, Coerce for type conversion, NumericRange for bounds (
lib/goliath/rack/validation/coerce.rb) - Validation errors are caught and returned as 400 Bad Request with details in the Params middleware layer (
lib/goliath/rack/params.rb)
Add response formatting for a new content type
- Create a new formatter class in lib/goliath/rack/formatters/ (e.g., csv.rb) with a serialize(object) method (
lib/goliath/rack/formatters/json.rb) - Register it in the Formatters registry mapping MIME type to formatter class (
lib/goliath/rack/formatters.rb) - Use DefaultMimeType or DefaultResponseFormat middleware to negotiate the format based on Accept header or params (
lib/goliath/rack/default_response_format.rb)
🔧Why these technologies
- EventMachine — Provides high-performance, non-blocking I/O reactor loop enabling thousands of concurrent connections with minimal memory footprint
- Ruby Fibers (1.9+) — Eliminates callback hell; each request executes in its own fiber enabling synchronous-looking code that transparently suspends on async I/O
- Rack API — Ensures compatibility with existing Ruby middleware ecosystem and allows reuse of proven, battle-tested middleware
- HTTP/1.1 Parser — Custom high-performance parser handles concurrent request parsing without blocking the reactor
⚖️Trade-offs already made
-
Fibers over callbacks
- Why: Developers are more familiar with linear, sequential code patterns
- Consequence: Requires Ruby 1.9+ and careful understanding of when fibers suspend/resume; not suitable for CPU-bound workloads
-
Rack-based middleware instead of custom pipeline
- Why: Reuse existing ecosystem and developer familiarity
- Consequence: Must bridge async Rack apps with Goliath's fiber-based execution; some Rack middleware may not be compatible without wrapping
-
Per-request fiber instead of thread pool
- Why: Fibers are lightweight (~KB vs ~MB per thread); enables true non-blocking scalability
- Consequence: Long-running CPU work blocks the reactor; not suitable for heavy computation without offloading
-
EventMachine as reactor instead of custom I/O loop
- Why: Proven, well-tested event loop with cross-platform support
- Consequence: Couples framework to EventMachine; EM bugs or performance issues affect all Goliath apps
🚫Non-goals (don't propose these)
- HTTP/2 or gRPC support (HTTP/1
🪤Traps & gotchas
Ruby 1.9.3+ is mandatory (mentioned explicitly in README); EventMachine reactor must be running (implicit in all examples but easy to forget in tests); Fiber-based execution means all blocking I/O must use async libraries (em-http-request, em-mongodb, etc.) not standard Net::HTTP; examples/config/ is a library of reusable patterns but not auto-loaded — you must manually require the specific config file in your app; the -sv flags in startup examples (development + verbose logging) should be replaced with production flags in live deployments.
🏗️Architecture
💡Concepts to learn
- Ruby Fibers (Coroutines) — Goliath's entire value proposition rests on Fibers (introduced Ruby 1.9+) allowing linear, synchronous-looking code to run atop an async reactor without callbacks; misunderstanding Fiber semantics leads to deadlocks or memory leaks.
- EventMachine Reactor Pattern — Goliath wraps an EventMachine reactor to multiplex I/O across thousands of connections; understanding the reactor's event loop, deferred objects, and callbacks is essential for debugging non-obvious async bugs.
- Non-blocking I/O and Async Suspension — Goliath's killer feature is that I/O operations transparently suspend and resume Fibers without developer intervention; knowing which operations are async (em-http-request) vs blocking (Net::HTTP) is critical for performance.
- Rack Middleware Pipeline — Goliath is Rack-compatible, so middleware composition (shown in examples/config/shared.rb and examples/auth_and_rate_limit.rb) follows standard Rack before/after/around patterns; this is the primary extension point.
- HTTP Keep-Alive and Pipelining — Goliath explicitly supports HTTP keep-alive and request pipelining (mentioned in README as differentiation from Thin), which reduces latency for high-frequency clients but requires careful connection state management.
- WebSocket Protocol (Full-Duplex Streaming) — Goliath's async model makes WebSocket support natural (see examples/config/websocket.rb); understanding the upgrade handshake and frame format is necessary for building real-time applications.
- Chunked Transfer Encoding — Goliath enables streaming responses via chunked encoding (examples/chunked_streaming.rb and examples/content_stream.rb); this allows sending large responses or real-time data without buffering, critical for low-latency APIs.
🔗Related repos
eventmachine/eventmachine— Core reactor library that powers Goliath's entire non-blocking I/O engine; understanding EventMachine's API is essential to debugging async behaviorrack/rack— Goliath implements the Rack interface, so middleware and app design patterns are inherited directly from the Rack ecosystemruby-grape/grape— Popular DSL for building REST APIs on Goliath; examples/grape/ shows production-grade integration pattern for this common use caseintridea/em-http-request— EventMachine-native HTTP client that Goliath developers must use instead of Net::HTTP to maintain non-blocking behavior in async operationsmacournoyer/thin— Predecessor async Ruby server (also EventMachine-based) that Goliath differs from by using Fibers instead of callbacks; understanding Thin's architecture clarifies why Goliath chose a different model
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test suite for lib/goliath/connection.rb
The connection.rb file is a core component handling all HTTP connections, but there's no visible test file for it in the repo structure. Given Goliath's focus on non-blocking async processing and fiber-based request handling, connection state management, streaming responses, and error handling need robust test coverage. This PR would add unit tests covering: fiber lifecycle, async request/response handling, chunked encoding, connection timeouts, and middleware chain execution in async contexts.
- [ ] Create spec/goliath/connection_spec.rb with test cases for connection initialization and lifecycle
- [ ] Add tests for async request processing and fiber suspension/resumption in lib/goliath/connection.rb
- [ ] Add tests for streaming response handling and chunked transfer encoding
- [ ] Add tests for error handling and connection cleanup in async contexts
- [ ] Ensure tests use EventMachine reactor testing patterns (em-spec or similar)
Add integration tests for middleware chain execution with async/await patterns
Examples like examples/async_aroundware_demo.rb and examples/auth_and_rate_limit.rb show async middleware support, but there's no visible test coverage validating that middleware chains work correctly with Goliath's fiber-based async model. This is critical because incorrect middleware ordering or state handling could silently break production deployments. A test suite here would validate the async middleware patterns documented in these examples.
- [ ] Create spec/goliath/middleware_spec.rb for testing async middleware chains
- [ ] Add tests for before/after middleware execution order with async operations (e.g., auth_and_rate_limit pattern)
- [ ] Add tests for error propagation through async middleware stacks
- [ ] Add tests for state isolation between concurrent requests in async middleware
- [ ] Reference examples/async_aroundware_demo.rb and examples/auth_and_rate_limit.rb in test scenarios
Add API documentation for lib/goliath/env.rb and request/response lifecycle
The env.rb file is central to Goliath's request handling (analogous to Rack's env), but there's no dedicated documentation explaining its structure, available properties, and how it flows through the async request lifecycle. This gap makes it difficult for new contributors to understand how to build async handlers. The .yardopts file indicates YARD documentation is used, but env.rb likely lacks comprehensive docs.
- [ ] Add YARD documentation to lib/goliath/env.rb documenting all available env properties and their async behavior
- [ ] Document the request lifecycle: parsing → env creation → middleware → async handler → response serialization
- [ ] Add code examples in YARD docs showing common patterns (accessing params, headers, async operations)
- [ ] Create doc/async_request_lifecycle.md explaining how fibers interact with the env object
- [ ] Regenerate docs via 'rake yard' and verify documentation renders correctly
🌿Good first issues
- Add RSpec tests for examples/early_abort.rb and examples/fiber_pool.rb: these files lack corresponding spec files unlike the structured test patterns in other examples, and testing early response termination + custom fiber pools would be valuable regression prevention.
- Document the em-http-request vs Net::HTTP decision trade-off in README.md: new developers constantly try blocking HTTP calls; add a 'Common Mistakes' section with before/after code showing why standard HTTP libraries fail in Goliath and how to use EM wrappers instead.
- Create examples/middleware_auth_template.rb: auth_and_rate_limit.rb exists but lacks a bare-bones authentication-only example for simple API key / JWT checking, making it harder for newcomers to add auth to minimal servers without cargo-culting unneeded rate limiting code.
⭐Top contributors
Click to expand
Top contributors
- @igrigorik — 31 commits
- @Juanmcuello — 9 commits
- @dj2 — 9 commits
- @janko — 8 commits
- @nolman — 6 commits
📝Recent commits
Click to expand
Recent commits
70f7493— bump 1.0.7 (igrigorik)0ac7573— Merge pull request #354 from romuloceccon/file-exists-deprecation (igrigorik)44d9ce0— Fix File.exists? warning on Ruby 3 (romuloceccon)bdbf254— Avoid warning due to 'headers=' being redefined (Juanmcuello)6d3b08d— Avoid warning for assigned variable not being used (Juanmcuello)a0a6d61— bump to 1.0.6 (igrigorik)a920d03— Merge pull request #343 from janko-m/stream-response-body (igrigorik)8c2b57f— Stream the response to the client (janko)06bdc53— Improve handling multiple requests to same connection (janko)1e27eb0— Don't continue calling #on_body if request is to be terminated (janko)
🔒Security observations
- High · Potential YAML Deserialization Vulnerability —
lib/goliath/rack/formatters/yaml.rb. The presence of lib/goliath/rack/formatters/yaml.rb suggests YAML serialization/deserialization functionality. YAML.load() in Ruby can execute arbitrary code when deserializing untrusted input, leading to remote code execution. Fix: Use YAML.safe_load() instead of YAML.load() for parsing untrusted input. Ensure strict type allowlisting is configured. - High · Potential XML External Entity (XXE) Injection —
lib/goliath/rack/formatters/xml.rb. The presence of lib/goliath/rack/formatters/xml.rb indicates XML parsing functionality. Without proper configuration, XML parsers may be vulnerable to XXE attacks, allowing attackers to read local files or perform SSRF attacks. Fix: Disable external entity processing and DTD parsing in XML parser. Use libraries with secure defaults or explicitly configure nokogiri/rexml with XXE protections enabled. - Medium · Missing Content Security Policy (CSP) Headers —
lib/goliath/rack/. No evidence of CSP middleware configuration visible in the rack directory. This could allow XSS attacks and other injection vulnerabilities to execute in the browser context. Fix: Implement Content Security Policy middleware to restrict script execution and resource loading. Add strict CSP headers to all HTTP responses. - Medium · Potential HTML/XSS Injection in HTML Formatter —
lib/goliath/rack/formatters/html.rb, examples/views/. The HTML formatter (lib/goliath/rack/formatters/html.rb) may render user input without proper escaping, especially given that examples include template rendering with HAML and ERB files. Fix: Ensure all user input is properly HTML-escaped before rendering. Use template engines with auto-escaping enabled by default. Implement output encoding middleware. - Medium · JSONP Endpoint Without Callback Validation —
lib/goliath/rack/jsonp.rb. The presence of lib/goliath/rack/jsonp.rb suggests JSONP support, which is inherently vulnerable to callback injection and cross-site request forgery if the callback parameter is not strictly validated. Fix: Validate callback function names against a strict whitelist pattern. Consider disabling JSONP in favor of CORS. If JSONP is required, ensure callbacks match ^[a-zA-Z0-9_.]+$ and implement CSRF tokens. - Medium · Missing Security Headers Configuration —
lib/goliath/rack/. No visible implementation of standard security headers (X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, etc.) in the rack middleware configuration. Fix: Implement middleware to add security headers: X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Strict-Transport-Security, X-XSS-Protection. - Medium · Database Interaction Without Visible ORM Safeguards —
examples/activerecord/. ActiveRecord example exists (examples/activerecord/) but parameterized query usage cannot be verified from file structure alone. Risk of SQL injection if raw queries are used. Fix: Use ActiveRecord's built-in parameterized query methods exclusively. Avoid string interpolation in database queries. Use query builders instead of raw SQL where possible. - Low · Missing Dependency Lock File Verification —
Gemfile, goliath.gemspec. Dependency management relies on Gemfile without evidence of locked versions (Gemfile.lock not visible in provided structure). This could allow transitive dependency vulnerabilities. Fix: Ensure Gemfile.lock is committed to version control and regularly audited. Use 'bundle audit' to check for known vulnerabilities in dependencies. Keep all gems updated. - Low · Sensitive Files in Examples Directory —
examples/config/. Example configuration files may contain patterns that developers copy into production code, potentially introducing security issues if they contain debug modes, weak defaults, or insecure examples. Fix: Clearly mark
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.