Skip to content

feat: add mix hammer.install Igniter task - #194

Merged
epinault merged 1 commit into
masterfrom
feat/igniter-installer
Aug 29, 2026
Merged

feat: add mix hammer.install Igniter task#194
epinault merged 1 commit into
masterfrom
feat/igniter-installer

Conversation

@epinault

Copy link
Copy Markdown
Contributor

Summary

  • Adds an Igniter installer so mix igniter.install hammer (or mix hammer.install on a project that already has Hammer) generates a MyApp.RateLimit module and adds it to the application's supervision tree.
  • --backend / -b accepts ets (default), atomic or redis. Because the Redis backend lives in the separate hammer_backend_redis package, --backend redis also adds that dependency and generates use Hammer, backend: Hammer.Redis with a url: child spec.
  • Igniter is an optional dependency: without it, mix hammer.install prints instructions to install Igniter (following Igniter's own optional-dependency template). No runtime impact for existing users.

This is part 1 of #157 (installer). It deliberately does not attempt the "patch my controller functions" half of that issue: Hammer has no global/per-route config — limits are defined at each call site via hit(key, scale, limit) — so a patcher can't know the key derivation, limits, or 429 handling a given app needs. The README addition points users at the Tutorial for that.

Changes

  • lib/mix/tasks/hammer.install.ex - the Mix.Tasks.Hammer.Install task (+ .Docs module, non-Igniter fallback)
  • test/mix/tasks/hammer.install_test.exs - Igniter.Test coverage: all three backends, dep added / not duplicated for redis, unknown backend reported as an issue, idempotent re-run
  • mix.exs / mix.lock - {:igniter, "~> 0.8", optional: true}
  • README.md - "Installing with Igniter" subsection
  • CHANGELOG.md - Unreleased entry

Generated output for --backend ets in an app named MyApp:

# lib/my_app/rate_limit.ex
defmodule MyApp.RateLimit do
  @moduledoc """
  Rate limiter for MyApp, backed by `:ets`.
  ...
  """

  use Hammer, backend: :ets
end

# lib/my_app/application.ex
children = [
  {MyApp.RateLimit, [clean_period: :timer.minutes(1)]},
  ...
]

Test Plan

  • mix test --warnings-as-errors --cover — 142 tests, 0 failures, 93.2% total coverage (task at 100%)
  • mix credo --strict, mix format --check-formatted, mix deps.unlock --check-unused
  • End-to-end in a fresh mix new --sup project with {:hammer, path: ...}: mix hammer.install generates the module + child spec, and MyApp.RateLimit.hit/3 returns {:allow, 1}, {:allow, 2}, {:deny, _} with limit 2
  • End-to-end mix hammer.install --backend redis: adds {:hammer_backend_redis, "~> 7.0"}, generated module compiles against hammer_backend_redis 7.1.1

Ticket

Refs: #157


🤖 Generated with Claude Code by Emmanuel Pinault

https://claude.ai/code/session_01JckHuT8GcW8Gzsai7vcpvT

Add an Igniter-based installer so `mix igniter.install hammer` (or
`mix hammer.install` on an existing project) generates a
`MyApp.RateLimit` module using `use Hammer, backend: ...` and adds it
to the application's supervision tree.

`--backend` (`-b`) accepts `ets` (default), `atomic` or `redis`; the
`redis` option also adds the `hammer_backend_redis` dependency since
that backend lives in a separate package. Unknown backends are reported
as an Igniter issue and the run is idempotent.

Igniter is declared as an optional dependency; without it the task
prints instructions to install Igniter, following Igniter's own
optional-dependency template.

Refs: #157

Co-Authored-By: Emmanuel Pinault <dev@pinault-family.us>
Claude-Session: https://claude.ai/code/session_01JckHuT8GcW8Gzsai7vcpvT
@epinault
epinault merged commit 92de8fa into master Aug 29, 2026
2 of 9 checks passed
epinault pushed a commit that referenced this pull request Aug 29, 2026
Since #194 the repo ships a Mix task; without :mix in the PLT dialyzer
reports Mix.Task callback info as missing. Dialyzer now passes clean.

Co-Authored-By: Emmanuel Pinault <dev@pinault-family.us>
Claude-Session: https://claude.ai/code/session_01JckHuT8GcW8Gzsai7vcpvT
epinault added a commit that referenced this pull request Sep 2, 2026
…196)

erlex is a transitive dev/test-only dependency of dialyxir; 0.2.9
rewrites the type-grammar precedence and adds mix erlex.typecheck.

Since #194 the repo ships a Mix task; without :mix in the PLT dialyzer
reports Mix.Task callback info as missing. Dialyzer now passes clean.

Verified: mix compile --warnings-as-errors, mix test (142 tests),
mix dialyzer, mix deps.unlock --check-unused.


Claude-Session: https://claude.ai/code/session_01JckHuT8GcW8Gzsai7vcpvT

Co-authored-by: epinault <dev@pinault-family.us>
@epinault epinault mentioned this pull request Sep 2, 2026
5 tasks
epinault added a commit that referenced this pull request Sep 2, 2026
- Bump version 7.4.1 -> 7.5.0 in mix.exs
- Promote Unreleased changelog section to 7.5.0 (#194, #197, #198)

Minor bump: the release adds the mix hammer.install Igniter task and
carries two TokenBucket ETS fixes, one of which changes the deny wait
from a flat 1000ms to the real time-to-next-token.


Claude-Session: https://claude.ai/code/session_011dH6kRtZqUkVpoGo79CKYG

Co-authored-by: epinault <dev@pinault-family.us>
@epinault
epinault deleted the feat/igniter-installer branch September 2, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant