libjpeg with image_optim gem on Heroku Cedar Stack (Ruby buildpack) - ruby-on-rails

I'm trying to get the image_optim gem to work with a Rails 4 app on Heroku's Cedar stack to optimize png/gif/jpeg images.
I threw the required binaries (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout) into /bin and set ENV['PATH'] = "#{Rails.root}/bin:#{ENV['PATH']}" in an initializer. This works for gifs and pngs, but I'm running into problems with jpegs.
In the rails console I get:
irb(main):001:0> `jpegoptim`
jpegoptim: error while loading shared libraries: libjpeg.so.8: cannot open shared object file: No such file or directory
How should I go about installing libjpeg on Heroku?

The correct way to deploy binaries to Heroku is to use buildpacks:
https://devcenter.heroku.com/articles/buildpacks
Use this one if you want to package up multiple binaries:
https://github.com/ddollar/heroku-buildpack-multi
There are a number of buildpacks already created for various binaries, but none for the ones you have listed.

I have created a gem that allows you to run image_optim on heroku:
https://github.com/mooktakim/image_optim_bin

You're probably looking for this: Heroku Image-Optim Buildpack
Or this: https://github.com/bobbus/image-optim-buildpack

Related

Do I need to build Ruby with jemalloc and use the gem if I'm using a Heroku buildpack?

Sample a Ruby (2.4.1) on Rails (4.2.8) app, configured with Puma and deployed on Heroku (cedar-16). Currently developing on a Mojave 10.14.5 MBP. I'm on a mission to cut down memory usage and recently discovered jemalloc via this post. I reinstalled Ruby (using RVM) with jemalloc enabled as proved by the following output - -lpthread -ljemalloc -lgmp -ldl -lobjc. I proceeded to add the jemalloc gem and bundle installed without a problem. I've also set up the Heroku buildpack and configured necessary environment variables.
However, with the gem in my Gemfile, I'm unable to run any rake/rails commands - rails c returns the following error, promptly followed by my Mac's fans firing up:
ruby(45487,0x10739c5c0) malloc: *** malloc_zone_unregister() failed for 0x7fff94a3f000
foreman start gets stuck at * Preloading application. All issues vanish & app works fine if I remove the gem.
Since I'm not privy to how Heroku buildpacks work and how that specific one is programmed exactly, my questions are as follows:
With the buildpack added, do I really need the gem installed in my project?
With the buildpack added, do I need a Ruby version compiled using jemalloc?
If I do need the gem, how do I get rid of the aforementioned error?
malloc gem was last released 5 years ago and it bundles a pretty old version of jemalloc lib (v3.4 and currently we have v5.2).
All the gem does, is adding jemalloc lib to LD_PRELOAD (or DYLD_INSERT_LIBRARIES on mac os) before executing ruby binary.
It shouldn't be needed if ruby is built against jemalloc library with --with-jemalloc flag.
So to answer your questions:
With the buildpack added, do I really need the gem installed in my project?
No, buildpack will handle everything automatically for you while deploying to heroku.
Actually, there might be a problem with conflicting jemalloc versions if you have the gem.
With the buildpack added, do I need a Ruby version compiled using jemalloc?
For local development? Technically no. But I would advise you to use exactly the same ruby version as you use on production to avoid suprises.
If I do need the gem, how do I get rid of the aforementioned error?
You don't need the gem. You can enable jemalloc by rebuilding your ruby with --with-jemalloc flag (as you did).
Here's a full list of steps:
# install jemalloc lib locally
brew install jemalloc
# reinstall ruby (with rbenv):
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 2.7.1
# or with rvm:
rvm reinstall 2.7.1 -C —with-jemalloc
# confirm ruby is using jemalloc (ruby >= 2.6)
ruby -r rbconfig -e "puts RbConfig::CONFIG['MAINLIBS']"
# or with ruby < 2.6
ruby -r rbconfig -e "puts RbConfig::CONFIG['LIBS']"
You might also need to rebuild gems with native extensions (though I'm not sure about this one):
See this question for how to do it: How do I get a list of gems that are installed that have native extensions?

Where are Ruby gems located on a server?

My understanding is that the gemfile in a Rails app only provides references to the actual code of these gems on your local computer. So when you're running your app locally, it's pulling the gem code from your local computer. What happens when you deploy though? The server runs your rails code, but does it also hold all the references in your gem file and automatically download them as well?
Yep. If you deploy on Heroku, you can see bundler doing its work and pulling down the gems.
As per the Bundler docs, you can use bundle show --paths to see exactly where your gems are being loaded from.
Additionally, if you aren't using bundler, you can use the command gem environment to see gem paths on the system.
See this existing answer for more info: How can I find where gem files are installed?

Heroku/Rails: How to install the GNU Scientific Library (GSL) on Heroku?

I need to install the GSL library on Heroku running a Rails (4.0.2) app to use some gems that depend on it.
Goal:
Install the GSL library to work with GSL and Similarity gems in Heroku.
Tried approaches:
Installing Ruby / GSL in Heroku Application: Heroku crashes after deploy. GSL gem is unable to find the lib. Trace: http://pastebin.com/CPcMUdCa
Tomwolfe's Heroku's Ruby buildpack adapted for using couchbase: Same issue.
Building Dependency Binaries for Heroku Applications: Vulcan is deprecated. More info on Heroku's Devcenter and on Github
I've tried following these steps (compiling binaries):
GSL 1.15 downloaded from ftp://ftp.gnu.org/gnu/gsl/gsl-1.15.tar.gz
Uncompressed and cd gsl-1.15
./configure
make clean
make
sudo make install
It works on my local environment but not in Heroku. Heroku doesn't allow sudo but it allows access with heroku run. The problem is that the file system is ephemeral and the dyno will only live as long as your console session.
Update:
I've also tried building my own Heroku Buildpack but I couldn't make it work. I tried using multipacks. I'm not a Heroku Buildpack expert so maybe it's the problem, I'm learning more about it to make a simple repository with an example and an extended explanation of this issue.
I had to use gsl1.16 on heroku and here is how I solved it:
First added gsl1.16 buildpack to the lists of buildpacks like
heroku buildpacks:add --index:3 git://github.com/gregory/heroku-gsl-buildpack.git#gsl-1.16
Which adds to my list of buildpacks, in my case got nodejs and ruby already. Hence --index=3
Then had to set LD_LIBRARY_PATH on heroku like
heroku config:set LD_LIBRARY_PATH=/app/vendor/gsl/lib
which points to 1.16. Seen around that some people use /app/vendor/gsl1/lib but wasn't my case.
and that's it.
I made a heroku buildpack a couple months ago for 1.15 and 1.16
just do:
heroku buildpacks:set git://github.com/gregory/heroku-gsl-buildpack.git#gsl-1.16
or
heroku buildpacks:set git://github.com/gregory/heroku-gsl-buildpack.git#gsl-1.15
You'll need to use a custom buildpack. Buildpacks allow you to define any additional dependencies outside of your project and package them with your slug which is used by the dynos. The buildpack you linked to (https://github.com/tomwolfe/heroku-buildpack-gsl-ruby) would be your best bet in getting everything working. I would open issues on their github repo if you are having issues, hopefully they can help you out

Heroku: Could not find a JavaScript runtime

In heroku app log I get:
2011-11-25T15:14:08+00:00 app[web.1]: /app/.bundle/gems/ruby/1.9.1/gems/execjs-1.2.9/lib/execjs
etect': Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a li
(ExecJS::RuntimeUnavailable)
Are execjs and therubyracer gems needed to run rails 3.1 app on heroku?
Given the error message I'm guessing this is a Rails 3.1 on the old stack, called Bamboo.
Heroku recommends the cedar stack for Rails 3.1 and they have a tutorial here on how to get that going.
You need to be using the heroku cedar stack and not bamboo.
Install JavaScript runtime environment in your systems by using following steps, as this is best way to solve the issue:
wget http://nodejs.org/dist/node-v0.1.31.tar.gz
tar xfv node-v0.1.31.tar.gz
cd node-v0.1.31
./configure
make
make install

Using Hunspell With Heroku

I'm building a Rails app that uses Hunspell and the hunspell-ffi gem so that Ruby can interface with it. I'm deploying the app to heroku, but unfortunately it needs Hunspell to be installed on the server in order for the gem to work.
Is there any way for me to install Hunspell on Heroku? Or am I going to have to migrate to EC2?
Thanks in advance :)
You need to build the required Hunspell library and include it in your Heroku project directly.
Heroku runs on 64-bit Ubuntu therefore the binary has to be compiled under that system. The best approach is to simply use Heroku's Vulcan build server to compile on a Heroku instance.
Compiling for Heroku
gem install vulcan
vulcan create vulcan-compile-me last argument is your own app name.
Download Hunspell source
Extract
vulcan build -v -s ./hunspell-1.3.2 Tells Vulcan to build it and downloads the finished product automatically to /tmp/hunspell..
The build server requires the cloudant add-on, this is installed automatically but you have to make sure to have a verified (credit card added) Heroku account. If you get errors in step six of no build output then do heroku addons:add cloudant --app vulcan-compile-me
Adding to Your Project
Extract the Heroku Vulcan build tar from /tmp
Copy the entire lib folder to vendor/hunspell in your project root directory
Tell Heroku where to look for libraries: heroku config:add LD_LIBRARY_PATH=vendor/hunspell/lib.
Install Dictionaries
Download some dictionaries from Open Office and add them to your project. A good location is a folder called dictionaries at root level. This path is then referenced when initializing Hunspell in Ruby.
http://extensions.services.openoffice.org/dictionary
ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/OpenOffice/contrib/
Using
Install your favorite Hunspell gem, I use hunspell-ffi. There is a newer gem for Hunspell but I prefer the previous FFI gem. To use initialize the Hunspell object with your dictionaries folder path and language (language match the dictionary file name).
dict = Hunspell.new("dictionaries", "en_US")
if dict.check('caribean') == false
suggestions = dict.suggest('caribean')
if (suggestions.size)
correction = suggestions.first # returns 'caribbean'
end
end
Vendoring for More Complex Projects
You can also vendor the library into your project by putting the tar built by the Vulcan server in the first step into a public accessible server such as Google Storage and then changing the Heroku build pack to download the tar on each instance startup.
heroku config:set BUILDPACK_URL=https://github.com/peterkeen/heroku-buildpack-vendorbinaries.git
The vendor build pack looks for a .vendor_urls file at the root level with HTTP links to the tar balls to install (needs to end in a new line to work).
http://commondatastorage.googleapis.com/developer.you.com/hunspell-heroku-1.3.tgz
Vendoring unpacks the tar into the root folder so the lib path for the Heroku settings would then just be "lib". heroku config:add LD_LIBRARY_PATH=lib
Unless I am mistaken or something has changed (I cannot find any evidence of this), you cannot install external native libraries on Heroku. If the library is not already installed (this is the case, I think, for ImageMagick, and perhaps others), you will not be able to use the gem.
Checkout this url: http://gems-summary.heroku.com/2011-07-19
It's freaking amazing how much support Heroku has for the gem community. So all you need to to is add the gem to your bundle since Hunspell is on rubygems, bundle install, and then deploy.
Gemfile
source 'http://rubygems.org'
gem 'rails', '3.0.5'
gem 'hunspell'
Then add to git:
git add .
git commit -m 'added hunspell'
Then bundle:
bundle
And deploy:
git push heroku
With Bundler, you should be able to install any gem. According to http://devcenter.heroku.com/articles/how-do-i-install-gems-for-my-app, "Almost any gem - even those with native dependencies - can be installed using Bundler. If there’s a specific gem that won’t install on Heroku, please submit a support ticket."
AFAIK, when your app is spun up, gems in the Gemfile are installed on-the-fly to the server your app is spun up to.
The Aspen stack has pre-installed gems, but you still should be able to add gems not pre-installed.
The bamboo stack has no pre-installed gems, so all gem dependencies must be declared explicitly. I believe that is the same for the Celadon stack.

Resources