Welcome to My Blog.

Here, you will find posts, links, and more about code (primarily Ruby), business (bootstrapped SaaS), and a little of everything in between.

Enabling Debugging in Campfire

Ruby's debugging story has improved dramatically in 3.x (and Rails).

I figured the best way to understand what's happening in Campfire would be to attach the debugger and step through some of the more interesting parts.

Unfortunately, I was greeted with a recurring error that often looked something like this:

<Thread:0x00000001276a7750@DEBUGGER__::Server::reader /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/gems/3.3.0/gems/debug-1.9.1/lib/debug/server.rb:44 aborting> terminated with exception (report_on_exception is true):
/Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/3.3.0/socket.rb:1128:in `unlink': No such file or directory @ apply2files - /var/folders/6q/xz6r4tqd4sl9qpbqkjlqj3dr0000gn/T/rdbg-501/rdbg-29191 (Errno::ENOENT)
	from /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/3.3.0/socket.rb:1128:in `ensure in unix_server_socket'
/Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/3.3.0/socket.rb:1128:in `unlink'	from /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/3.3.0/socket.rb:1128:in `unix_server_socket'
	from /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/3.3.0/socket.rb:1169:in `unix_server_loop'
	from /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/gems/3.3.0/gems/debug-1.9.1/lib/debug/server.rb:502:in `accept'
	from /Users/scott/.asdf/installs/ruby/3.3.0/lib/ruby/gems/3.3.0/gems/debug-1.9.1/lib/debug/server.rb:49:in `block in activate'

At first, I was convinced that debugging was busted on my computer. But I spun up a new project, and everything worked as expected.

Then, I thought about the error above showing up multiple times and the problems with threads I had previously mentioned.

I restarted the process without cluster mode enabled for Puma (WEB_CONCURRENCY=0) and could connect the debugger as expected.

From here, I decided to compare the puma.rb file in Campfire to the one in the empty Rails 7.1 project I just spun up, and I found the problem.

In the Puma configuration file, cluster mode is enabled if workers is greater than 0.

In a fresh Rails 7.1 puma.rb file, the worker configuration looks like this:

if ENV["RAILS_ENV"] == "production"
  require "concurrent-ruby"
  worker_count = Integer(ENV.fetch("WEB_CONCURRENCY") { Concurrent.physical_processor_count })
  workers worker_count if worker_count > 1
end

However, in Campfire, the RAILS_ENV check is removed

worker_count = (Concurrent.processor_count * 0.666).ceil
workers ENV.fetch("WEB_CONCURRENCY") { worker_count }

My guess is that with Campfire being a chat app with lots of connectivity, they opted for Puma's cluster mode by default.

The good news is you can disable cluster mode in Campfire without changing any source. Just set the WEB_CONCURRENCY ENV to 0.

Something like this should do the trick:

WEB_CONCURRENCY=0 rdbg -n --open=vscode -c -- bin/rails server -p 3000

#

Setting Up Campfire on Localhost

David Kimura at Drifting Ruby has some good videos on setting Campfire up outside the Once installer. Outside of the 3.3 RC1 and stringio issues, I was running into another issue: I could not generate thumbnails when running on localhost. The thumbnails generated as expected when using Puma Dev. Still, on localhost, they were failing, and worse, I would typically end up with one broken thumbnail variant per thread pool worker.

First, here are my setup steps:

  1. Download the source
  2. Run bin/setup (I had to remove rbenv from this file since I use ASDF these days)
  3. From the rails console, run, WebPush.generate_key and copy the keys into ENV variables VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY
  4. Add the msgpack gem to my GemFile

With all of this in place, https://campfire.test worked as expected.

However, when starting the server via bundle exec rails server (on an M1 MBP with Sonoma 14.3), the thumbnails of images were missing. I could click on the thumbnails and see them in the lightbox but not in the chat window.

Digging into the database, I could see they were not being analyzed, but I had no idea why.

Then I saw the following in the logs:

objc[84578]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called.
objc[84578]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.

The thread running ActiveJob running the ActiveStorage Analyze job was crashing.

A little searching led me to this bug thread and a suggestion to set OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES. A quick server reboot, and everything works as expected.

Before I got here, I also tried disabling cluster mode in Puma, WEB_CONCURRENCY=0 bundle exec rails s, which solved the problem.

I submitted this as a bug to 37Signals. I am not sure if this is just something on my computer or not, so I would try it without these changes first.

Update: 37Signals confirmed this is a known issue. The env variable is actually set in the .pumadev file which is why I did. not see the issue when using Puma Dev.

#

A few new apps I am using in 2024

Typefully - a few options exist for posting to social media without logging in first. I am trying to get back into writing/sharing, and this seems like the best option.

If Threads adds an API, all will be right.

Cronometer - A replacement for MyFitnessPal. Short review: It is better in every way. It is easier to use, quicker and costs less.

I don't track calories as much these days; with a change in my diet recently, I wanted to be a little more diligent.

Craft is a notes app similar to Notion, but I find it more responsive and easier to use. Craft syncs across all my devices and has been a joy for the last few weeks.

Via X: twitter.com/scottw/st...

#

The Hidden Month

New Year, new ambitions: start your own business and take control of your time and finances.

But here's the harsh reality: the adrenaline fades, and most give up within weeks.

Here's a suggestion...

Dedicate your weekends this year. Spend four hours each on Saturday and Sunday building your business.

That's a solid month (26 days) of focused work without sacrificing sleep or your regular schedule.

Speed to market is overrated. Success comes from execution and continuous improvement, week after week, month after month.

Posted initially to X: twitter.com/scottw/st...

#

Troubleshooting Broken Software Tools Still Sucks

20+ years of professionally building software, and here is how my last hour or so went.

heroku login -> zsh: killed heroku login

hmmm...why did ZSH kill Heroku? It turns out it is just reporting what happened.

Open the crash reports and get a bunch of text I barely understand.

I remember that I have a second brain that knows what this crap means. ChatGPT, can you help me?

It does a decent job of educating me on what the reports (segfault on the main thread implies not even the hand of God can save this process).

When in doubt, just re-install.

No dice.

Google shows me others with similar problems, but none related to Heroku, and nothing that looks promising.

I wonder what the (brew) Doctor thinks about this (Heroku was installed this way).

The doctor takes her good old time getting back to me on this older Mac. But when she does respond, she says, "Dawg, your shit is F'ed Up!"

I am paraphrasing, but there are unlinked things, kegs with no formula,, dry taps, an unbrewed dylibs, and likely most importantly, this:

This is weird because I had previously checked for an update after an OS update, and I had tried to re-install the tools just to be safe.

In both cases, it said, "there are no updates, go away".

Anywho, I run the following:

sudo rm -rf /Library/Developer/CommandLineTools

sudo xcode-select --install

Eventually, notice the popup window (because why install them from the terminal), click OK to continue, and 10 minutes or so later, we are back in business.

The key takeaways:

  1. This shit isn't hard, it just takes patience.
  2. Even those who have done it for a long time still get stuck.
  3. There is nothing wrong with yelling profanities at a computer from the comfort of your basement.
#

Finding Joy in Fitness: The Importance of Enjoying Your Training

Last week's early morning gym commutes were far from ideal. One morning, I attempted to leave and discovered I had a dead battery (actually, two dead batteries). Two days later, I had a close encounter with a deer while driving. Temperatures were in the low 30s at best.

However, at approximately 4:35 am on a Monday (today), I found myself not only commuting to the gym again but also feeling quite excited to get to work.
It struck me then that it all comes down to finding the type of training you genuinely enjoy. While there may be exercises considered "the best" or "better," even engaging in the most mediocre exercise is far better for you than doing nothing.

This wasn't always the case for me. It took some trial and error, along with the willingness to start something, fully commit to it, and then be open to finding something that I both enjoyed and that yielded better results.

Ultimately, what truly matters is taking that initial step and sticking with it. It is crucial to listen to your body and determine what it will take to enjoy the work.

#

Charlie Munge:

The world isn't driven by greed. It's driven by envy.

#

Ruby Enumerable#any?

At first glance, this is not what I was expecting:

[false, false, false].any? => false

But a quick glance at the docs:

The method returns true if the block ever returns a value other than false or nil

This can be handy for doing a bunch of small tests and detecting if anything passed.

#