← Extractions

Toolbelt of a Seasoned Bug Hunter — debugging a Rails reload slowdown

Damir Zekić's wroclove.rb 2018 talk recounts an 'Odyssey' of diagnosing a progressively slowing Rails test-reload loop. He walks through reproducing the bug, using git bisect and a custom linear-search script, investigating memory leaks with heap dumps (heapy), rendering flame graphs, digging into Rails' routing code and Ruby's undef_method in C, and ultimately tracing the root cause to the monolith/granite framework mounting controllers at Spring boot time.

Model
claude-opus-4-7
Ingestion
97bc0a8f
Input tokens
100,629
fresh
47,005
cached
44,307
cache write
9,317
Output tokens
8,847
Duration
128.4s
Roundtrips
4
Tool calls
13
Cost
$0.00
Nodes/edges extracted
21 / 38
Read set (nodes/edges)
72 / 2

Nodes (21)

update Damir Zekić person
attrs (empty) {"role" => "Ruby programmer"}
description Conference speaker. Conference speaker at wroclove.rb 2018. Remote Ruby programmer who enjoys pair programming with his cat Midori. Worke...
short_description Conference speaker. Ruby developer and conference speaker; worked on the monolith/granite business-actions framework.
update Toolbelt of a Seasoned Bug Hunter talk
description Talk at wroclove.rb 2018. Damir Zekić's wroclove.rb 2018 talk subtitled '2016: A Debugging Odyssey in Six Chapters with an Epilogue'. Recounts ...
short_description Talk at wroclove.rb 2018. Story-driven talk on advanced debugging tools applied to a Rails reload slowdown.
update wroclove.rb 2018 event
No changes recorded.
create Spring tool
kind (empty) tool
name (empty) Spring
slug (empty) spring
attrs (empty) {"category" => "library"}
description (empty) Rails preloader gem that loads a Rails application into memory once and forks copies for each test run, console, or c...
short_description (empty) Rails application preloader that keeps the app in memory between commands.
create Guard tool
kind (empty) tool
name (empty) Guard
slug (empty) guard
attrs (empty) {"category" => "library"}
description (empty) Ruby tool that watches files and automatically re-runs tests (or other tasks) when files change. Used together with S...
short_description (empty) Ruby file-watcher that reruns tests on file change.
create git bisect tool
kind (empty) tool
name (empty) git bisect
slug (empty) git-bisect
attrs (empty) {"category" => "tool"}
description (empty) Git subcommand that binary-searches commit history between a known-good and a known-bad commit, running a user script...
short_description (empty) Git command performing binary search through history to find a bad commit.
create find-slow script tool
kind (empty) tool
name (empty) find-slow script
slug (empty) find-slow-script
attrs (empty) {"category" => "tool"}
description (empty) Ad-hoc Ruby script the speaker wrote to extend git bisect when no known-good commit existed: checks out each previous...
short_description (empty) Custom Ruby script that linearly walks git history to find a non-slow commit.
create heapy tool
kind (empty) tool
name (empty) heapy
slug (empty) heapy
attrs (empty) {"category" => "library"}
description (empty) Ruby gem installed as a command-line tool that parses ObjectSpace heap-dump JSON files and summarizes how many object...
short_description (empty) Ruby gem for analyzing heap dumps produced by ObjectSpace.
create ObjectSpace heap dumps concept
kind (empty) concept
name (empty) ObjectSpace heap dumps
slug (empty) objectspace-heap-dumps
attrs (empty) {"category" => "practice"}
description (empty) Ruby's built-in facility (ObjectSpace + allocation tracing) to dump every live object to a file where each line is a ...
short_description (empty) Built-in Ruby mechanism to snapshot all live objects to a JSON-lines file.
create Flame Graphs concept
kind (empty) concept
name (empty) Flame Graphs
slug (empty) flame-graphs
attrs (empty) {"category" => "practice"}
description (empty) Visualization technique where the x-axis represents aggregated stack frames and the y-axis represents call depth, let...
short_description (empty) Stacked visualization of sampled call-stack frames showing where time is spent.
create monolith framework project
kind (empty) project
name (empty) monolith framework
slug (empty) monolith-framework
attrs (empty) {"status" => "superseded", "license" => "closed-source"}
description (empty) Internal 'business-action framework' built on top of Rails that let developers encapsulate commands/operations with v...
short_description (empty) Arkency's in-house business-actions framework for monolithic Rails apps (predecessor of granite).
create granite project
kind (empty) project
name (empty) granite
slug (empty) granite
attrs (empty) {"status" => "active", "license" => "open-source", "repository" => "github.com/.../granite"}
description (empty) Open-source successor to the monolith framework, announced publicly for the first time during this talk. A business-a...
short_description (empty) Open-source business-actions architecture gem for Rails apps.
create Rails RouteSet clear concept
kind (empty) concept
name (empty) Rails RouteSet clear
slug (empty) rails-routeset-clear
attrs (empty) {"category" => "architecture"}
description (empty) ActionDispatch::Routing::RouteSet#clear iterates over the _path_helpers and _url_helpers modules and calls undef_meth...
short_description (empty) Rails routing internal that undef_methods all URL/path helpers on every reload.
create Ruby undef_method performance concept
kind (empty) concept
name (empty) Ruby undef_method performance
slug (empty) ruby-undef_method-performance
attrs (empty) {"category" => "architecture"}
description (empty) Benchmark shown in the talk: defining and undef-ing methods across N modules-included-in-objects is far from linear i...
short_description (empty) undef_method scales super-linearly and spends half its time clearing the method cache.
create Ruby memory retention behavior concept
kind (empty) concept
name (empty) Ruby memory retention behavior
slug (empty) ruby-memory-retention-behavior
attrs (empty) {"category" => "architecture"}
description (empty) Ruby's garbage collector reclaims objects inside the Ruby heap but does not shrink the process by returning memory to...
short_description (empty) Ruby's GC frees objects but does not return freed heap pages to the OS.
create DescendantsTracker concept
kind (empty) concept
name (empty) DescendantsTracker
slug (empty) descendantstracker
attrs (empty) {"category" => "architecture"}
description (empty) ActiveSupport::DescendantsTracker is mixed into every class in a Rails app and stores, in a class-level class-variabl...
short_description (empty) ActiveSupport module that keeps a hash of every class and its subclasses.
create Know thy app takeaway
kind (empty) takeaway
name (empty) Know thy app
slug (empty) know-thy-app
attrs (empty) {"type" => "lesson-learned"}
description (empty) The closing lesson of the talk: debugging subtle, long-running performance bugs requires knowing not just your own co...
short_description (empty) Know your code, your framework, your libraries, and the language — otherwise bugs like this are inevitable.
create Don't create controllers at Rails boot time takeaway
kind (empty) takeaway
name (empty) Don't create controllers at Rails boot time
slug (empty) don-t-create-controllers-at-rails-boot-time
attrs (empty) {"type" => "lesson-learned"}
description (empty) Concrete lesson from the monolith debugging: mounting business-action objects (which generated controllers) onto rout...
short_description (empty) Creating controllers before Spring forks makes them immortal across reloads.
create Use Ruby to debug Ruby takeaway
kind (empty) takeaway
name (empty) Use Ruby to debug Ruby
slug (empty) use-ruby-to-debug-ruby
attrs (empty) {"type" => "recommendation"}
description (empty) Takeaway repeated throughout the talk: the speaker leaned on small Ruby scripts (linear-search across git history, di...
short_description (empty) When off-the-shelf tools don't fit, writing a small Ruby script is often the fastest diagnostic tool.
create Stable commits enable bisect takeaway
kind (empty) takeaway
name (empty) Stable commits enable bisect
slug (empty) stable-commits-enable-bisect
attrs (empty) {"type" => "recommendation"}
description (empty) Practical recommendation: to use git bisect effectively, every commit on the main history must be independently build...
short_description (empty) Keep every commit green so git bisect (and similar tooling) remains usable.
create Was debugging dev-environment performance worth it vs. ditching Spring/Guard? question
kind (empty) question
name (empty) Was debugging dev-environment performance worth it vs. ditching Spring/Guard?
slug (empty) was-debugging-dev-environment-performance-worth-it-vs-ditching-spring-guard
attrs (empty) {"answer_summary" => "Yes — with 50–200 developers running tests daily, Spring's speedup over the first few runs was ...
description (empty) Audience Q&A question asking whether the multi-week debugging effort was worth it versus simply removing Spring or Gu...
short_description (empty) Q&A: was the long debugging investment justified instead of dropping Spring/Guard?

Edges (38)

update Damir ZekićauthoredToolbelt of a Seasoned Bug Hunter
context (empty) Delivered the talk at wroclove.rb 2018.
update Toolbelt of a Seasoned Bug Hunterpresented_atwroclove.rb 2018
context (empty) Talk given at wroclove.rb 2018 on 2018-03-16.
create Damir Zekićattendedwroclove.rb 2018
context (empty) Spoke at the conference.
relation (empty) attended
source_node_id (empty) 93c1df89-64bd-4e49-b555-d6b618dd6f35
target_node_id (empty) 9243ef2c-21bb-4f23-b450-9ecd87882dfe
create Damir Zekićworks_onmonolith framework
attrs (empty) {"role" => "contributor"}
context (empty) Worked on the in-house business-actions framework that was the subject of the debugging story.
relation (empty) works_on
source_node_id (empty) 93c1df89-64bd-4e49-b555-d6b618dd6f35
target_node_id (empty) 427481c5-23b4-45bf-a5d8-ce6dc5917c20
create Damir Zekićworks_ongranite
attrs (empty) {"role" => "contributor"}
context (empty) Announces granite at the talk as the open-sourced successor to monolith.
relation (empty) works_on
source_node_id (empty) 93c1df89-64bd-4e49-b555-d6b618dd6f35
target_node_id (empty) 25015725-35e3-4aec-ae7a-cc0639ce7059
create Damir ZekićusesSpring
context (empty) Describes using Spring in the team's development workflow.
relation (empty) uses
source_node_id (empty) 93c1df89-64bd-4e49-b555-d6b618dd6f35
target_node_id (empty) a182d808-d06a-4ac8-b5ca-97e0dacd1d0e
create Damir ZekićusesGuard
context (empty) Describes using Guard to automatically run tests on file changes.
relation (empty) uses
source_node_id (empty) 93c1df89-64bd-4e49-b555-d6b618dd6f35
target_node_id (empty) 120a09f1-2974-46e8-899f-5b2c40554e78
create Toolbelt of a Seasoned Bug HunteraboutSpring
context (empty) Spring's preloader/fork model is central to the reload-slowdown bug investigated.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) a182d808-d06a-4ac8-b5ca-97e0dacd1d0e
create Toolbelt of a Seasoned Bug HunteraboutGuard
context (empty) The bug was observed through Guard's test re-runs after file changes.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 120a09f1-2974-46e8-899f-5b2c40554e78
create Toolbelt of a Seasoned Bug Hunteraboutgit bisect
context (empty) Speaker explains and uses git bisect as a first-line debugging tool.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) db652a7a-07e4-44b7-98fe-15ba29f719e0
create Toolbelt of a Seasoned Bug Hunteraboutfind-slow script
context (empty) Speaker wrote a custom Ruby script to linearly walk git history when no good commit was known.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 4bdf8947-a5d3-4555-88a3-82f45387f502
create Toolbelt of a Seasoned Bug HunteraboutObjectSpace heap dumps
context (empty) Uses Ruby's built-in heap-dump facility to investigate a suspected memory leak.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 73c2e3f4-1523-42ba-aa2e-4a22a738a3b1
create Toolbelt of a Seasoned Bug Hunteraboutheapy
context (empty) Uses the heapy gem to analyze heap dumps across GC generations.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) af27119d-8034-40ca-a11d-80747227291d
create Toolbelt of a Seasoned Bug HunteraboutRuby memory retention behavior
context (empty) Explains that Ruby does not return freed memory to the OS, complicating leak diagnosis.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 94622f7e-a1ff-4bb1-b2ad-9b10fcd72274
create Toolbelt of a Seasoned Bug HunteraboutFlame Graphs
context (empty) Renders flame graphs of Rails startup to compare successive boots and locate the growing function.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 0e6fd01c-57c8-4805-ae3d-106d9b86a619
create Toolbelt of a Seasoned Bug HunteraboutRails RouteSet clear
context (empty) Traces the slowdown to RouteSet#clear undef_methoding URL/path helpers on every reload.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) a3df8cde-7d91-4c7c-8afe-9dd5c264f35e
create Toolbelt of a Seasoned Bug HunteraboutRuby undef_method performance
context (empty) Benchmarks and source-dives undef_method, showing super-linear cost and method-cache clearing overhead.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 06520dd1-5953-40db-b7c7-2be35c9b6bde
create Toolbelt of a Seasoned Bug Hunteraboutmonolith framework
context (empty) Root cause of the bug was monolith's boot-time controller mounting.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 427481c5-23b4-45bf-a5d8-ce6dc5917c20
create Toolbelt of a Seasoned Bug Hunteraboutgranite
context (empty) Publicly announces granite as the open-sourced successor to monolith.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 25015725-35e3-4aec-ae7a-cc0639ce7059
create Toolbelt of a Seasoned Bug HunteraboutDescendantsTracker
context (empty) Epilogue highlights ActiveSupport::DescendantsTracker as a framework cause of classes never being GC'd.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 66f8eadd-4b37-421c-899a-c557b58cc253
create Toolbelt of a Seasoned Bug HunteraboutRuby on Rails
context (empty) The app under debugging is a monolithic Rails application.
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) 7aac705a-0987-49f2-b665-9d4e08a6acee
create Toolbelt of a Seasoned Bug HunteraboutRuby
context (empty) Deep dive into Ruby internals (undef_method, ObjectSpace, memory behavior).
relation (empty) about
source_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
target_node_id (empty) c7f25b33-06c9-460e-aca7-fe993123ebee
create monolith frameworkrelated_toRuby on Rails
context (empty) monolith is a business-action framework built on top of Rails.
relation (empty) related_to
source_node_id (empty) 427481c5-23b4-45bf-a5d8-ce6dc5917c20
target_node_id (empty) 7aac705a-0987-49f2-b665-9d4e08a6acee
create graniterelated_toRuby on Rails
context (empty) granite is a business-actions architecture gem for Rails apps.
relation (empty) related_to
source_node_id (empty) 25015725-35e3-4aec-ae7a-cc0639ce7059
target_node_id (empty) 7aac705a-0987-49f2-b665-9d4e08a6acee
create graniterelated_tomonolith framework
context (empty) granite is the open-sourced successor to the internal monolith framework.
relation (empty) related_to
source_node_id (empty) 25015725-35e3-4aec-ae7a-cc0639ce7059
target_node_id (empty) 427481c5-23b4-45bf-a5d8-ce6dc5917c20
create Rails RouteSet clearrelated_toRuby on Rails
context (empty) Rails internal method in ActionDispatch::Routing::RouteSet.
relation (empty) related_to
source_node_id (empty) a3df8cde-7d91-4c7c-8afe-9dd5c264f35e
target_node_id (empty) 7aac705a-0987-49f2-b665-9d4e08a6acee
create DescendantsTrackerrelated_toRuby on Rails
context (empty) ActiveSupport module shipped with Rails.
relation (empty) related_to
source_node_id (empty) 66f8eadd-4b37-421c-899a-c557b58cc253
target_node_id (empty) 7aac705a-0987-49f2-b665-9d4e08a6acee
create heapyrelated_toRuby
context (empty) Analyzes Ruby ObjectSpace heap dumps.
relation (empty) related_to
source_node_id (empty) af27119d-8034-40ca-a11d-80747227291d
target_node_id (empty) c7f25b33-06c9-460e-aca7-fe993123ebee
create ObjectSpace heap dumpsrelated_toRuby
context (empty) Built into Ruby's ObjectSpace module.
relation (empty) related_to
source_node_id (empty) 73c2e3f4-1523-42ba-aa2e-4a22a738a3b1
target_node_id (empty) c7f25b33-06c9-460e-aca7-fe993123ebee
create Ruby memory retention behaviorrelated_toRuby
context (empty) Behavior specific to MRI Ruby's garbage collector and heap management.
relation (empty) related_to
source_node_id (empty) 94622f7e-a1ff-4bb1-b2ad-9b10fcd72274
target_node_id (empty) c7f25b33-06c9-460e-aca7-fe993123ebee
create Ruby undef_method performancerelated_toRuby
context (empty) Implementation detail of MRI Ruby's method table and method cache.
relation (empty) related_to
source_node_id (empty) 06520dd1-5953-40db-b7c7-2be35c9b6bde
target_node_id (empty) c7f25b33-06c9-460e-aca7-fe993123ebee
create Know thy appfrom_talkToolbelt of a Seasoned Bug Hunter
context (empty) Closing lesson of the talk.
relation (empty) from_talk
source_node_id (empty) 69f782f8-a1da-4649-a423-32926cf02a98
target_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
create Don't create controllers at Rails boot timefrom_talkToolbelt of a Seasoned Bug Hunter
context (empty) Concrete fix identified at the end of the debugging odyssey.
relation (empty) from_talk
source_node_id (empty) c47f4e4b-7644-43ef-9d99-efdd514d7fd7
target_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
create Use Ruby to debug Rubyfrom_talkToolbelt of a Seasoned Bug Hunter
context (empty) Repeated pattern throughout the debugging odyssey.
relation (empty) from_talk
source_node_id (empty) c1c1e52f-de1d-46dc-99e4-fe8a8935c745
target_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
create Stable commits enable bisectfrom_talkToolbelt of a Seasoned Bug Hunter
context (empty) Caveat highlighted during the git bisect chapter.
relation (empty) from_talk
source_node_id (empty) 5777130a-2b88-4c75-bb0f-17e7c829d1cd
target_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
create Was debugging dev-environment performance worth it vs. ditching Spring/Guard?asked_atToolbelt of a Seasoned Bug Hunter
context (empty) Q&A question at the end of the talk.
relation (empty) asked_at
source_node_id (empty) 30bf6c20-cf2f-42eb-a8ea-f26310ddd711
target_node_id (empty) 24118e0e-f605-4f4c-914a-526607d647c1
create Was debugging dev-environment performance worth it vs. ditching Spring/Guard?aboutSpring
context (empty) Asks whether it would have been simpler to drop Spring.
relation (empty) about
source_node_id (empty) 30bf6c20-cf2f-42eb-a8ea-f26310ddd711
target_node_id (empty) a182d808-d06a-4ac8-b5ca-97e0dacd1d0e
create Was debugging dev-environment performance worth it vs. ditching Spring/Guard?aboutGuard
context (empty) Asks whether it would have been simpler to drop Guard.
relation (empty) about
source_node_id (empty) 30bf6c20-cf2f-42eb-a8ea-f26310ddd711
target_node_id (empty) 120a09f1-2974-46e8-899f-5b2c40554e78

Read set

72 nodes

tool Ruby on Rails search_nodes talk Business logic in Ruby search_nodes takeaway Replay-Based Debugging search_nodes talk Rubyana Gems and the Ractorous Rubetta Stones! search_nodes tool Rails 5.2 search_nodes talk Orchestrating video transcoding in ruby search_nodes talk When REST is Not Enough: Implementing Alternative Protocols in Ruby on Rails search_nodes tool Iodine search_nodes person Akira Matsuda search_nodes talk Introducing Sorbet into your Ruby codebase search_nodes concept Static Page Caching via nginx search_nodes talk Better WebPerformance with Rails search_nodes concept Rails Reload-Safe ES Configuration search_nodes takeaway Serve preheated static pages via nginx search_nodes concept Cache Preheating search_nodes question What is an enterprise Rails application? search_nodes talk No-build Utopia: Modern User Experiences with Rails & Web Standards search_nodes question Is rendering from cached pages with server-side includes possible in Rails? search_nodes concept Preloading and Prefetching search_nodes concept Breadth-First Search for Code Removal search_nodes talk Removing Code with Breadth-First Search search_nodes concept Waterfall Analysis search_nodes tool Babel search_nodes takeaway Watch WebAssembly for real performance wins search_nodes tool Grafana search_nodes tool webpagetest.org search_nodes resource Rocket Real-Time Benchmark search_nodes tool Rust search_nodes takeaway Sign serverlessforruby.org petition search_nodes tool Flow search_nodes tool Ruby Event Store search_nodes tool rails_event_store search_nodes tool Action Cable search_nodes tool JSON API Resources search_nodes talk Working with RailsEventStore in Cashflow Management System search_nodes question Can parts of Eventide, Rails Event Store and Trailblazer be combined in one project? search_nodes concept Active Record search_nodes concept Trailblazer Workflow search_nodes talk Multi-region data governance in Rails application search_nodes event wroclove.rb 2018 search_nodes event wroclove.rb 2019 search_nodes event wroclove.rb 2024 search_nodes event wroclove.rb 2022 search_nodes event wroclove.rb 2023 search_nodes event wroclove.rb 2026 search_nodes event wroclove.rb 2025 search_nodes talk Building LLM powered applications in Ruby search_nodes talk Counterintuitive Rails pt. 2 search_nodes talk Counterintuitive Rails pt. 1 search_nodes talk Debug like a scientist search_nodes talk Fix Production Bugs 20x Faster search_nodes talk Toolbelt of a Seasoned Bug Hunter search_nodes+get_node_edges concept Global Interpreter Lock search_nodes tool Heroku search_nodes tool dry-struct search_nodes tool Ruby search_nodes person Koichi Sasada search_nodes concept Method References in Ruby search_nodes takeaway Upgrade Ruby version for free speed search_nodes talk Methods Gem for Ruby Method References search_nodes talk JRuby: Professional-Grade Ruby search_nodes talk An Introduction to Test Bench search_nodes talk Securing Rails applications search_nodes takeaway Use Refinements for Coordinated Modernization search_nodes talk Nightmare neighbours caveats of Rails based mutlitenancy search_nodes concept Refinements search_nodes person Damir Zekić search_nodes person Adam Okoń search_nodes person Julik Tarkhanov search_nodes person Emiliano Della Casa search_nodes concept Ruby Module Customization Mechanics search_nodes concept ActiveSupport Core Extensions search_nodes

2 edges