bug_bunny 4.8.0 → 4.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.agents/skills/documentation-writer/SKILL.md +45 -0
- data/.agents/skills/gem-release/SKILL.md +114 -0
- data/.agents/skills/quality-code/SKILL.md +51 -0
- data/.agents/skills/sentry/SKILL.md +135 -0
- data/.agents/skills/sentry/references/api-endpoints.md +147 -0
- data/.agents/skills/sentry/scripts/sentry.rb +194 -0
- data/.agents/skills/skill-builder/SKILL.md +232 -0
- data/.agents/skills/skill-manager/SKILL.md +172 -0
- data/.agents/skills/skill-manager/scripts/sync.rb +310 -0
- data/.agents/skills/yard/SKILL.md +311 -0
- data/.agents/skills/yard/references/tipos.md +144 -0
- data/CHANGELOG.md +8 -0
- data/CLAUDE.md +28 -231
- data/lib/bug_bunny/version.rb +1 -1
- data/skill/SKILL.md +230 -0
- data/skill/references/client-middleware.md +144 -0
- data/skill/references/consumer.md +104 -0
- data/skill/references/controller.md +105 -0
- data/skill/references/errores.md +97 -0
- data/skill/references/resource.md +116 -0
- data/skill/references/routing.md +82 -0
- data/skill/references/testing.md +138 -0
- data/skills.lock +24 -0
- data/skills.yml +19 -0
- metadata +24 -28
- data/.claude/commands/gem-ai-setup.md +0 -174
- data/.claude/commands/pr.md +0 -53
- data/.claude/commands/release.md +0 -52
- data/.claude/commands/rubocop.md +0 -22
- data/.claude/commands/service-ai-setup.md +0 -168
- data/.claude/commands/test.md +0 -28
- data/.claude/commands/yard.md +0 -46
- data/docs/_index.md +0 -50
- data/docs/ai/_index.md +0 -56
- data/docs/ai/antipatterns.md +0 -166
- data/docs/ai/api.md +0 -251
- data/docs/ai/architecture.md +0 -92
- data/docs/ai/errors.md +0 -158
- data/docs/ai/faq_external.md +0 -133
- data/docs/ai/faq_internal.md +0 -86
- data/docs/ai/glossary.md +0 -45
- data/docs/concepts.md +0 -140
- data/docs/howto/controller.md +0 -194
- data/docs/howto/middleware_client.md +0 -119
- data/docs/howto/middleware_consumer.md +0 -127
- data/docs/howto/rails.md +0 -214
- data/docs/howto/resource.md +0 -200
- data/docs/howto/routing.md +0 -133
- data/docs/howto/testing.md +0 -259
- data/docs/howto/tracing.md +0 -119
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
Generate or update the complete AI documentation suite for this microservice.
|
|
2
|
-
|
|
3
|
-
This skill is invoked automatically by `/pr`. It can also be run standalone.
|
|
4
|
-
|
|
5
|
-
The same quality standard as BugBunny's `docs/ai/` applies here — self-contained chunks, RAG-optimized, no introductory prose.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Step 1 — Discover the current state
|
|
10
|
-
|
|
11
|
-
Read in order:
|
|
12
|
-
1. `docs/_index.md` — if it exists, lists all files and their purpose
|
|
13
|
-
2. `docs/ai/_index.md` — if it exists, current profile and file list
|
|
14
|
-
3. `CLAUDE.md` — service purpose, architecture, dependencies
|
|
15
|
-
4. `config/services.yml` — declared dependencies (other services this one talks to)
|
|
16
|
-
5. `config/routes.rb` or `config/initializers/bug_bunny_routes.rb` — what this service exposes
|
|
17
|
-
|
|
18
|
-
If `docs/ai/` does not exist yet, this is a **first-time generation**. Create from scratch.
|
|
19
|
-
If it exists, **update only the sections affected by the changes in this PR**.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Step 2 — Profile
|
|
24
|
-
|
|
25
|
-
Microservices always use the **full profile** with `contracts.md` instead of `api.md`:
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
docs/ai/
|
|
29
|
-
_index.md
|
|
30
|
-
glossary.md
|
|
31
|
-
architecture.md
|
|
32
|
-
contracts.md ← what this service exposes (queues, endpoints, events)
|
|
33
|
-
faq_internal.md
|
|
34
|
-
faq_external.md
|
|
35
|
-
antipatterns.md
|
|
36
|
-
errors.md
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Step 3 — Analyze the codebase
|
|
42
|
-
|
|
43
|
-
Read:
|
|
44
|
-
- `app/` — controllers, models, workers, services
|
|
45
|
-
- `config/` — routes, initializers, services.yml
|
|
46
|
-
- `lib/` — custom libraries
|
|
47
|
-
- `spec/` — usage patterns and edge cases
|
|
48
|
-
- `CHANGELOG.md` or git log — what changed in this PR
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Step 4 — Generate or update each file
|
|
53
|
-
|
|
54
|
-
Apply the same RAG optimization rules as `gem-ai-setup`:
|
|
55
|
-
1. Each section ≤ 400 tokens, self-contained
|
|
56
|
-
2. `faq_*.md` strict Q&A format, H3 question, answer ≤ 150 words
|
|
57
|
-
3. `glossary.md` one entry per term, 1-3 lines
|
|
58
|
-
4. `errors.md` one entry per error, cause + reproduction + resolution
|
|
59
|
-
5. No introductory prose
|
|
60
|
-
|
|
61
|
-
### `_index.md`
|
|
62
|
-
|
|
63
|
-
Frontmatter manifest. Use `kind: microservice` and `transports:` listing all transports used (bug_bunny, http, etc.). List every file with its audience.
|
|
64
|
-
|
|
65
|
-
```yaml
|
|
66
|
-
---
|
|
67
|
-
type: knowledge_base
|
|
68
|
-
kind: microservice
|
|
69
|
-
name: service_name
|
|
70
|
-
version: main # microservices don't have semver — use branch or date
|
|
71
|
-
profile: full
|
|
72
|
-
language: ruby
|
|
73
|
-
audiences:
|
|
74
|
-
- internal
|
|
75
|
-
- external
|
|
76
|
-
transports:
|
|
77
|
-
- bug_bunny # list actual transports used
|
|
78
|
-
- http
|
|
79
|
-
files:
|
|
80
|
-
- path: glossary.md
|
|
81
|
-
audience: [internal, external]
|
|
82
|
-
- path: architecture.md
|
|
83
|
-
audience: [internal]
|
|
84
|
-
- path: contracts.md
|
|
85
|
-
audience: [external]
|
|
86
|
-
...
|
|
87
|
-
---
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### `glossary.md`
|
|
91
|
-
|
|
92
|
-
Domain terms specific to this service's business domain and technical patterns.
|
|
93
|
-
|
|
94
|
-
### `architecture.md`
|
|
95
|
-
|
|
96
|
-
Internal-facing. Include:
|
|
97
|
-
- Service responsibility (one paragraph)
|
|
98
|
-
- Component map
|
|
99
|
-
- Data flows for the main operations
|
|
100
|
-
- External dependencies and how they're used
|
|
101
|
-
- Background jobs and their triggers
|
|
102
|
-
|
|
103
|
-
### `contracts.md`
|
|
104
|
-
|
|
105
|
-
External-facing. The complete contract this service exposes. Include:
|
|
106
|
-
|
|
107
|
-
**BugBunny queues (if applicable):**
|
|
108
|
-
- Queue name, exchange, routing key, exchange type
|
|
109
|
-
- For each route: method, path, request format, response format, possible errors
|
|
110
|
-
- Example request and response payloads
|
|
111
|
-
|
|
112
|
-
**HTTP endpoints (if applicable):**
|
|
113
|
-
- Method, path, parameters, response format
|
|
114
|
-
- Authentication requirements
|
|
115
|
-
|
|
116
|
-
**Events published (if applicable):**
|
|
117
|
-
- Exchange, routing key, payload format
|
|
118
|
-
|
|
119
|
-
### `faq_internal.md`
|
|
120
|
-
|
|
121
|
-
Q&A for the service developer. Cover:
|
|
122
|
-
- How to add a new route or endpoint
|
|
123
|
-
- How background jobs work and how to add one
|
|
124
|
-
- How to add a new service dependency
|
|
125
|
-
- Non-obvious architectural decisions
|
|
126
|
-
|
|
127
|
-
### `faq_external.md`
|
|
128
|
-
|
|
129
|
-
Q&A for developers of other services that consume this one. Cover:
|
|
130
|
-
- How to make a request to this service
|
|
131
|
-
- What errors to expect and how to handle them
|
|
132
|
-
- How to handle retries and timeouts
|
|
133
|
-
- How to test integrations against this service
|
|
134
|
-
|
|
135
|
-
### `antipatterns.md`
|
|
136
|
-
|
|
137
|
-
Common mistakes when interacting with or modifying this service.
|
|
138
|
-
|
|
139
|
-
### `errors.md`
|
|
140
|
-
|
|
141
|
-
All error responses this service can return. For each:
|
|
142
|
-
- HTTP status / error code
|
|
143
|
-
- When it occurs
|
|
144
|
-
- What the response body looks like
|
|
145
|
-
- How the caller should handle it
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Step 5 — Update docs/howto/ and README.md
|
|
150
|
-
|
|
151
|
-
Read `docs/_index.md` to discover which human docs exist.
|
|
152
|
-
Update sections affected by this PR's changes.
|
|
153
|
-
Update `README.md` last — after `docs/howto/` is updated.
|
|
154
|
-
|
|
155
|
-
README structure for a microservice:
|
|
156
|
-
1. Service purpose (one paragraph)
|
|
157
|
-
2. Transports (BugBunny queue name, HTTP base URL)
|
|
158
|
-
3. Quick start — how another service calls this one
|
|
159
|
-
4. Links to `docs/ai/contracts.md` for full contract reference
|
|
160
|
-
|
|
161
|
-
---
|
|
162
|
-
|
|
163
|
-
## Step 6 — Show diff and wait for approval
|
|
164
|
-
|
|
165
|
-
Show the complete diff of all generated/updated files.
|
|
166
|
-
Wait for developer approval before proceeding to PR creation.
|
|
167
|
-
The developer may adjust content before confirming.
|
|
168
|
-
Do NOT create the PR until the docs are approved.
|
data/.claude/commands/test.md
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
Run RSpec tests for BugBunny. Usage: /test [path]
|
|
2
|
-
|
|
3
|
-
Ejecutá la suite de tests de BugBunny con Ruby 3.3.8.
|
|
4
|
-
|
|
5
|
-
## Comando base
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
source /opt/homebrew/opt/chruby/share/chruby/chruby.sh && chruby ruby-3.3.8 && bundle exec rspec
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Si se pasa un path como argumento, corré solo ese archivo o directorio:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
source /opt/homebrew/opt/chruby/share/chruby/chruby.sh && chruby ruby-3.3.8 && bundle exec rspec $ARGUMENTS
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Después de correr los tests
|
|
18
|
-
|
|
19
|
-
- Si hay failures: analizá el error, identificá la causa raíz, proponé el fix al usuario antes de tocar código
|
|
20
|
-
- Si hay warnings de deprecación: reportalos al usuario
|
|
21
|
-
- Si todos pasan: confirmá con el conteo de ejemplos y tiempo de ejecución
|
|
22
|
-
|
|
23
|
-
## Convenciones de RSpec en este proyecto
|
|
24
|
-
|
|
25
|
-
- Tests en `spec/`
|
|
26
|
-
- Sin mocks de RabbitMQ real — usar doubles de Bunny
|
|
27
|
-
- Describir comportamiento, no implementación
|
|
28
|
-
- Un `context` por escenario, `it` con descripción en español o inglés consistente con el archivo
|
data/.claude/commands/yard.md
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
Validate and generate YARD documentation for BugBunny. Usage: /yard
|
|
2
|
-
|
|
3
|
-
Verificá y generá la documentación YARD de la gema.
|
|
4
|
-
|
|
5
|
-
## Comandos
|
|
6
|
-
|
|
7
|
-
Generar docs:
|
|
8
|
-
```bash
|
|
9
|
-
source /opt/homebrew/opt/chruby/share/chruby/chruby.sh && chruby ruby-3.3.8 && bundle exec yard doc
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
Ver métodos sin documentar:
|
|
13
|
-
```bash
|
|
14
|
-
source /opt/homebrew/opt/chruby/share/chruby/chruby.sh && chruby ruby-3.3.8 && bundle exec yard stats --list-undoc
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Estándar YARD de este proyecto
|
|
18
|
-
|
|
19
|
-
Todo método público nuevo o modificado debe tener:
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
# Descripción breve en una línea.
|
|
23
|
-
#
|
|
24
|
-
# Descripción extendida opcional si la firma no es autoexplicativa.
|
|
25
|
-
#
|
|
26
|
-
# @param nombre [Tipo] Descripción del parámetro
|
|
27
|
-
# @return [Tipo] Descripción del valor de retorno
|
|
28
|
-
# @raise [ClaseError] Condición bajo la cual se lanza
|
|
29
|
-
# @example
|
|
30
|
-
# resultado = mi_metodo(arg)
|
|
31
|
-
def mi_metodo(nombre)
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Tipos comunes en este proyecto
|
|
35
|
-
|
|
36
|
-
- `[String]`, `[Integer]`, `[Boolean]`, `[Hash]`, `[Array]`, `[Symbol]`
|
|
37
|
-
- `[Bunny::Session]`, `[Bunny::Channel]`, `[Bunny::MessageProperties]`
|
|
38
|
-
- `[BugBunny::Session]`, `[BugBunny::Request]`, `[BugBunny::Configuration]`
|
|
39
|
-
- `[Proc, nil]` para callbacks opcionales
|
|
40
|
-
- `[void]` para métodos sin return value relevante
|
|
41
|
-
|
|
42
|
-
## Después de correr
|
|
43
|
-
|
|
44
|
-
- Reportá los métodos públicos sin documentar
|
|
45
|
-
- No documentar métodos privados (YARD los ignora por defecto con `private`)
|
|
46
|
-
- No documentar métodos triviales (`attr_reader`, `attr_accessor`) salvo que necesiten contexto
|
data/docs/_index.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# docs/_index.md — Documentation Manifest
|
|
2
|
-
|
|
3
|
-
This file is the source of truth for the `docs/` directory structure.
|
|
4
|
-
It is read by the `/release` command to know which files to generate or update.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## Human documentation (developers integrating BugBunny)
|
|
9
|
-
|
|
10
|
-
| File | Purpose |
|
|
11
|
-
|---|---|
|
|
12
|
-
| `concepts.md` | AMQP in 5 min, architecture diagram, RPC vs fire-and-forget, connection pool |
|
|
13
|
-
| `howto/routing.md` | Routes DSL: `resources`, `namespace`, `member`, `collection`, `recognize` |
|
|
14
|
-
| `howto/controller.md` | `params`, `before_action`, `after_action`, `around_action`, `rescue_from`, `render` |
|
|
15
|
-
| `howto/resource.md` | CRUD methods, typed vs dynamic attributes, dirty tracking, validations, `.with` |
|
|
16
|
-
| `howto/middleware_client.md` | Client-side middlewares: built-ins, custom, usage in Client and Resource |
|
|
17
|
-
| `howto/middleware_consumer.md` | Consumer-side middlewares: execution order, writing, registering |
|
|
18
|
-
| `howto/tracing.md` | Trace context propagation: `rpc_reply_headers`, `on_rpc_reply`, consumer middleware |
|
|
19
|
-
| `howto/rails.md` | Full Rails setup: initializer, connection pool, Zeitwerk, Puma, Sidekiq, K8s health checks |
|
|
20
|
-
| `howto/testing.md` | Bunny doubles, unit tests for controllers/middleware, integration helper |
|
|
21
|
-
|
|
22
|
-
These files are referenced by `README.md`. Update them before updating the README.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## AI documentation (agents consuming or maintaining BugBunny)
|
|
27
|
-
|
|
28
|
-
Managed by `docs/ai/_index.md`. See that file for the full manifest and audience breakdown.
|
|
29
|
-
|
|
30
|
-
| File | Audience | Purpose |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| `ai/_index.md` | internal + external | Manifest: version, profile, file index |
|
|
33
|
-
| `ai/glossary.md` | internal + external | Domain terms with precise definitions |
|
|
34
|
-
| `ai/architecture.md` | internal | Internal patterns, component map, data flows |
|
|
35
|
-
| `ai/api.md` | external | Public API contracts |
|
|
36
|
-
| `ai/faq_internal.md` | internal | Q&A for gem maintainers |
|
|
37
|
-
| `ai/faq_external.md` | external | Q&A for gem integrators |
|
|
38
|
-
| `ai/antipatterns.md` | internal + external | What NOT to do and why |
|
|
39
|
-
| `ai/errors.md` | external | All exceptions with cause and resolution |
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Update rules for `/release`
|
|
44
|
-
|
|
45
|
-
1. Run tests first. If they fail, stop.
|
|
46
|
-
2. Read this file to discover all files to update.
|
|
47
|
-
3. For each file in **Human documentation**: update only sections affected by the changes in this release.
|
|
48
|
-
4. For each file in **AI documentation**: update only sections affected by the changes. Update `version` in `ai/_index.md`.
|
|
49
|
-
5. Update `README.md` last — it depends on `docs/howto/` being up to date.
|
|
50
|
-
6. Show the full diff to the developer and wait for approval before touching version or CHANGELOG.
|
data/docs/ai/_index.md
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: knowledge_base
|
|
3
|
-
kind: gem
|
|
4
|
-
name: bug_bunny
|
|
5
|
-
version: 4.8.0
|
|
6
|
-
profile: full
|
|
7
|
-
language: ruby
|
|
8
|
-
generated_by: gem-ai-setup@1.0.0
|
|
9
|
-
audiences:
|
|
10
|
-
- internal
|
|
11
|
-
- external
|
|
12
|
-
files:
|
|
13
|
-
- path: glossary.md
|
|
14
|
-
audience: [internal, external]
|
|
15
|
-
- path: architecture.md
|
|
16
|
-
audience: [internal]
|
|
17
|
-
- path: api.md
|
|
18
|
-
audience: [external]
|
|
19
|
-
- path: faq_internal.md
|
|
20
|
-
audience: [internal]
|
|
21
|
-
- path: faq_external.md
|
|
22
|
-
audience: [external]
|
|
23
|
-
- path: antipatterns.md
|
|
24
|
-
audience: [internal, external]
|
|
25
|
-
- path: errors.md
|
|
26
|
-
audience: [external]
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
## What is BugBunny?
|
|
30
|
-
|
|
31
|
-
BugBunny is a Ruby gem that implements a RESTful routing layer over AMQP (RabbitMQ). It lets microservices communicate via RabbitMQ using familiar HTTP patterns: verbs (GET, POST, PUT, DELETE), controllers, declarative routes, synchronous RPC, and fire-and-forget.
|
|
32
|
-
|
|
33
|
-
**Problem solved:** Eliminates direct HTTP coupling between microservices. RabbitMQ acts as the message bus with the same ergonomics as a web framework.
|
|
34
|
-
|
|
35
|
-
## Version
|
|
36
|
-
|
|
37
|
-
4.8.0 — April 2026
|
|
38
|
-
|
|
39
|
-
## Key features in this version
|
|
40
|
-
|
|
41
|
-
- Namespace routing (`namespace :admin { resources :users }`)
|
|
42
|
-
- `after_action` filter (runs after action, not after `before_action` halts)
|
|
43
|
-
- `render(headers:)` — inject custom headers into RPC replies
|
|
44
|
-
- `Consumer#shutdown` — explicit graceful shutdown with health check cleanup
|
|
45
|
-
- `Configuration#validate!` — invoked automatically at end of `BugBunny.configure`
|
|
46
|
-
- Producer/Session caching per connection slot (prevents double-consumer AMQP error)
|
|
47
|
-
- Expanded `SENSITIVE_KEYS` filter in `safe_log`
|
|
48
|
-
- `ConsumerMiddleware::Stack` mutex for thread-safe registration
|
|
49
|
-
|
|
50
|
-
## How to use this knowledge base
|
|
51
|
-
|
|
52
|
-
- **Building an integration** → start with `api.md`, then `faq_external.md`
|
|
53
|
-
- **Debugging errors** → `errors.md`
|
|
54
|
-
- **Avoiding mistakes** → `antipatterns.md`
|
|
55
|
-
- **Understanding internals** → `architecture.md`, then `faq_internal.md`
|
|
56
|
-
- **Domain vocabulary** → `glossary.md`
|
data/docs/ai/antipatterns.md
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
## Antipatterns
|
|
2
|
-
|
|
3
|
-
### Running Producer and Consumer in the same process thread
|
|
4
|
-
|
|
5
|
-
**Wrong:**
|
|
6
|
-
```ruby
|
|
7
|
-
# In the same Puma process
|
|
8
|
-
Thread.new { BugBunny::Consumer.new(conn).subscribe(..., block: true) }
|
|
9
|
-
BugBunny::Resource.find(1) # uses a different connection slot — works but is wrong architecturally
|
|
10
|
-
```
|
|
11
|
-
|
|
12
|
-
**Why it's wrong:** The Consumer is a blocking loop designed to run in a dedicated worker process. Running it inside Puma wastes threads and ties service lifetime to the web server. If the web server restarts, the consumer dies too.
|
|
13
|
-
|
|
14
|
-
**Correct:** Run the Consumer as a separate process (Rake task, separate container/Dockerfile).
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
### Creating a new Client or Producer per request
|
|
19
|
-
|
|
20
|
-
**Wrong:**
|
|
21
|
-
```ruby
|
|
22
|
-
def show
|
|
23
|
-
client = BugBunny::Client.new(pool: MY_POOL) # new client on every request
|
|
24
|
-
client.request(...)
|
|
25
|
-
end
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Why it's wrong:** `Client` itself is cheap, but creating it with a block configures a new middleware stack. More importantly, if you bypass `Resource` and call `Producer` directly, creating a new `Producer` on an already-used channel causes an AMQP `basic_consume` conflict.
|
|
29
|
-
|
|
30
|
-
**Correct:** Use `Resource` (which caches Client → Session → Producer per connection slot) or create the `Client` once at application boot.
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
### Setting `Resource.connection_pool` inside a request
|
|
35
|
-
|
|
36
|
-
**Wrong:**
|
|
37
|
-
```ruby
|
|
38
|
-
class OrdersController < ApplicationController
|
|
39
|
-
def index
|
|
40
|
-
BugBunny::Resource.connection_pool = ConnectionPool.new(...) { BugBunny.create_connection }
|
|
41
|
-
Order.all
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Why it's wrong:** The pool is a global class-level setting. Reassigning it in a request creates a race condition and leaks connections.
|
|
47
|
-
|
|
48
|
-
**Correct:** Set `connection_pool` once in the initializer at boot.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
### Calling `.with` proxy more than once
|
|
53
|
-
|
|
54
|
-
**Wrong:**
|
|
55
|
-
```ruby
|
|
56
|
-
scope = Order.with(exchange: 'priority')
|
|
57
|
-
scope.find(1)
|
|
58
|
-
scope.find(2) # raises BugBunny::Error — ScopeProxy is single-use
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
**Why it's wrong:** `ScopeProxy#method_missing` sets `@used = true` on the first call. A second call raises.
|
|
62
|
-
|
|
63
|
-
**Correct:** Use the block form of `.with` for multiple calls within the same scope:
|
|
64
|
-
```ruby
|
|
65
|
-
Order.with(exchange: 'priority') do
|
|
66
|
-
Order.find(1)
|
|
67
|
-
Order.find(2)
|
|
68
|
-
end
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
### Adding `RaiseError` or `JsonResponse` manually to a Resource middleware stack
|
|
74
|
-
|
|
75
|
-
**Wrong:**
|
|
76
|
-
```ruby
|
|
77
|
-
class Order < BugBunny::Resource
|
|
78
|
-
client_middleware do |stack|
|
|
79
|
-
stack.use BugBunny::Middleware::RaiseError # already added by Resource
|
|
80
|
-
stack.use BugBunny::Middleware::JsonResponse # already added by Resource
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**Why it's wrong:** `Resource#bug_bunny_client` always adds `RaiseError` and `JsonResponse` as the innermost middlewares. Adding them again wraps the response in a second parsing pass, causing errors.
|
|
86
|
-
|
|
87
|
-
**Correct:** Only add custom middlewares in `client_middleware`. Never add the built-ins.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
### Calling `render` multiple times in an action or filter
|
|
92
|
-
|
|
93
|
-
**Wrong:**
|
|
94
|
-
```ruby
|
|
95
|
-
def show
|
|
96
|
-
render status: :ok, json: user
|
|
97
|
-
render status: :not_found, json: { error: 'Not found' } # second render — first one wins
|
|
98
|
-
end
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
**Why it's wrong:** The second `render` call overwrites `@rendered_response`. Behavior is undefined and dependent on execution order.
|
|
102
|
-
|
|
103
|
-
**Correct:** Use early returns or `return render(...)` to ensure only one render is called.
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
### Raising exceptions from `rpc_reply_headers` or `on_rpc_reply`
|
|
108
|
-
|
|
109
|
-
**Wrong:**
|
|
110
|
-
```ruby
|
|
111
|
-
config.rpc_reply_headers = -> { { 'X-Trace-Id' => Tracer.header! } } # Tracer.header! may raise
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Why it's wrong:** An exception in `rpc_reply_headers` propagates into the Consumer's `reply` method, corrupting the RPC reply and causing the caller to timeout.
|
|
115
|
-
|
|
116
|
-
**Correct:** Wrap the proc body in a rescue:
|
|
117
|
-
```ruby
|
|
118
|
-
config.rpc_reply_headers = -> { { 'X-Trace-Id' => (Tracer.header rescue nil) } }
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
### Declaring exchanges with incompatible options after first declaration
|
|
124
|
-
|
|
125
|
-
**Wrong:**
|
|
126
|
-
```ruby
|
|
127
|
-
# Service A declares exchange as non-durable
|
|
128
|
-
BugBunny.configure { |c| c.exchange_options = { durable: false } }
|
|
129
|
-
|
|
130
|
-
# Service B (or a later boot) declares the same exchange as durable
|
|
131
|
-
BugBunny.configure { |c| c.exchange_options = { durable: true } }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**Why it's wrong:** RabbitMQ raises a channel error (406 PRECONDITION_FAILED) if you try to redeclare an exchange with different attributes. This crashes the channel.
|
|
135
|
-
|
|
136
|
-
**Correct:** Agree on exchange options across all services. Use `{ durable: true }` in all production services.
|
|
137
|
-
|
|
138
|
-
---
|
|
139
|
-
|
|
140
|
-
### Using `Resource` without a connection pool
|
|
141
|
-
|
|
142
|
-
**Wrong:**
|
|
143
|
-
```ruby
|
|
144
|
-
Order.find(1) # BugBunny::Error: Connection pool missing for Order
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
**Why it's wrong:** `Resource.bug_bunny_client` raises if `connection_pool` is nil.
|
|
148
|
-
|
|
149
|
-
**Correct:** Always set `BugBunny::Resource.connection_pool` (or a subclass-specific pool) before making calls. Do this in the initializer.
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
### Calling `logger.debug "..."` directly inside BugBunny classes
|
|
154
|
-
|
|
155
|
-
**Wrong:**
|
|
156
|
-
```ruby
|
|
157
|
-
logger.debug "Processing #{message}" # eager interpolation, ignores debug level
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Why it's wrong:** String interpolation happens regardless of log level, wasting CPU. Also bypasses `safe_log`'s sensitive key filtering.
|
|
161
|
-
|
|
162
|
-
**Correct:**
|
|
163
|
-
```ruby
|
|
164
|
-
safe_log(:debug, 'component.event', key: value)
|
|
165
|
-
# safe_log passes blocks to logger.debug { ... } internally
|
|
166
|
-
```
|