HubSpot / hubspot-api-ruby

HubSpot API Ruby Client Libraries for V3 version of the API
Apache License 2.0
112 stars 51 forks source link

Crashing in Getting Started #320

Open sbecka opened 3 months ago

sbecka commented 3 months ago

Hello, I'm trying to use this gem for the first time with a private app. Whenever the last line of code contacts = client.crm.contacts.basic_api.get_page runs from the Getting Started section, I get this error: objc[18591]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. objc[18591]: +[__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.

ruby "3.3.0" gem "rails", "6.1.7.7" hubspot-api-client (18.0.0) json (~ > 2.1, >= 2.1.0) typhoeus (~> 1.4.0)

michael-berger-czi commented 3 months ago

I got this working by disabling Spring: export DISABLE_SPRING=true

Samsinite commented 2 months ago

I just wanted to chime in my two cents, as I have encountered this issue today. The reason for this error is occuring is that this library either directly or indirectly (probably more likely, I go into more details below on what I think the cause is) links to the macOS Foundation framework, and Objective-C classes defined by the macOS Foundation framework are fork-unsafe. https://blog.phusion.nl/2017/10/13/why-ruby-app-servers-break-on-macos-high-sierra-and-what-can-be-done-about-it/ does a pretty good job explaining this issue in detail.

The solution is to make sure that the dynamic library at issue is loaded before the fork occurs. With puma (which forks when running in cluster mode) this can be done by telling it to load offending the library before it forks:

before_fork do
  # load offending library here
end

I'm pretty sure I've narrowed this issue down to Typhoeus, because calling

require 'ethon'
Ethon::Curl.init

before a fork occurs eliminates the issue entirely in my application on my local machine.

For rails applications there is a simple solution, just tell rails to load the dynamic library in an initializer, all initializers are ran before the applicaiton will be forked.

I believe the library that hubspot is using that causes this issue is typhoeus, as it uses libcurl under the hood, and the initialization of libcurl is not safe to run inside of a fork. Curl v8.2.0 moved macOS specific calls into a global init call that can be called before forking (https://github.com/curl/curl/commit/c7308592fb8ba213fc2c1bb6ad39781df45bd84a). The Typhoeus Ethon library used to wrap libcurl does have an init function, if this function is called before a fork occurs, then it will fix the issue.

A simple solution to this problem is to create a rails generator that defines a hubspot-api-ruby initializer that runs: config/initializers/hubspot-api-ruby.rb:

require 'ethon'
Ethon::Curl.init

And to recommend that rails users run this as part of the setup process. I would also add documentation to the readme regarding this setup for those running this gem in other frameworks. It is worth pointing out that this is only an issue on OSX.

Other options are: