Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to deploy to heroku? #151

Open
buncis opened this issue Jul 30, 2021 · 9 comments
Open

how to deploy to heroku? #151

buncis opened this issue Jul 30, 2021 · 9 comments
Labels

Comments

@buncis
Copy link
Contributor

buncis commented Jul 30, 2021

when I want to deploy to heroku

the application always failed to build with this error message

PyCall::LibPythonFunctionNotFound: Unable to find the required symbol in libpython: _Py_NoneStruct

heroku logs -t

       Using rails 6.1.4
       Using rails_admin 2.2.0
       Installing pycall 1.4.1 with native extensions
       Fetching numpy 0.4.0
       Installing numpy 0.4.0
       Fetching pandas 0.3.8
       Installing pandas 0.3.8
       Bundle complete! 20 Gemfile dependencies, 77 gems now installed.
       Gems in the groups 'development' and 'test' were not installed.
       Bundled gems are installed into `./vendor/bundle`
       Bundle completed (6.72s)
       Cleaning up the bundler cache.
-----> Detecting rake tasks
 !
 !     Could not detect rake tasks
 !     ensure you can run `$ bundle exec rake -P` against your app
 !     and using the production group of your Gemfile.
 !     rake aborted!
 !     PyCall::LibPythonFunctionNotFound: Unable to find the required symbol in libpython: _Py_NoneStruct
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
...
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:59:in `load'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/rake_module.rb:29:in `load_rakefile'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:710:in `raw_load_rakefile'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:104:in `block in load_rakefile'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:186:in `standard_exception_handling'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:103:in `load_rakefile'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:82:in `block in run'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:186:in `standard_exception_handling'
 !     /tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:80:in `run'
 !     /tmp/build_403b9e21/bin/rake:5:in `<main>'
 !
/tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/helpers/rake_runner.rb:106:in `load_rake_tasks!': Could not detect rake tasks (LanguagePack::Helpers::RakeRunner::CannotLoadRakefileError)
ensure you can run `$ bundle exec rake -P` against your app
and using the production group of your Gemfile.
rake aborted!
PyCall::LibPythonFunctionNotFound: Unable to find the required symbol in libpython: _Py_NoneStruct
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/activesupport-6.1.4/lib/active_support/dependencies.rb:332:in `block in require'
...
/tmp/build_403b9e21/vendor/bundle/ruby/2.7.0/gems/rake-13.0.6/lib/rake/application.rb:80:in `run'
/tmp/build_403b9e21/bin/rake:5:in `<main>'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/ruby.rb:1007:in `rake'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/rails4.rb:78:in `block (2 levels) in run_assets_precompile_rake_task'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/base.rb:190:in `log'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/rails4.rb:72:in `block in run_assets_precompile_rake_task'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/instrument.rb:18:in `block (2 levels) in instrument'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/instrument.rb:40:in `yield_with_block_depth'
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/lib/language_pack/instrument.rb:17:in `block in instrument'
	....
	from /tmp/codon/tmp/buildpacks/50d5eddf222a9b7326028041d4e6509f915ccf2c/bin/support/ruby_compile:15:in `<main>'
 !     Push rejected, failed to compile Ruby app.
 !     Push failed
@buncis
Copy link
Contributor Author

buncis commented Jul 30, 2021

apparently this is because default python that heroku use is not builded with --enable-shared

thus why our build is failed because pycall.rb need python that use enable-shared

to fix this problem here are the steps

first, set your heroku buildpack

since using pycall.rb our apps is consist of multiple stack (Python, Ruby, Javascript)
to set the buildpack what you need to do are

  1. clean the current buildpack
    heroku buildpacks:clear

  2. add the needed buildpack with order (-i set the order)
    heroku buildpacks:add heroku/python - i 1
    heroku buildpacks:add heroku/nodejs -i 2
    heroku buildpacks:add heroku/ruby -i 3

optional step, clear your heroku build cache

heroku sometimes use build cache instead compiling from scratch, to clear it
https://help.heroku.com/18PI5RSY/how-do-i-clear-the-build-cache
first install the plugin
heroku plugins:install heroku-builds
Then use the following command to clear the cache:
heroku builds:cache:purge
The cache will be rebuilt on the next deploy. If you do not have any new code to deploy, you can push an empty commit.

$ git commit --allow-empty -m "Purge cache"
$ git push heroku master

second, add neccessary file & scripts to your rails project

the python buildpacks from heroku need two file to run, build and install the dependencies

  1. runtime.txt this is file where u declared ur python version
    my runtime.txt
    python-3.8.10

  2. requirements.txt this is file where u declare python package that you use
    my requirements.txt

openpyxl==3.0.7
numpy==1.21.1
pandas==1.3.1

put those 2 files on root of your rails app folder, they are on same folder with your Gemfile and .ruby-version

third, make heroku use python that have --enable-shared config

this is essentials since our beloved pycall.rb depends on it, it cannot work with python without --enable-shared
there is multiple way to achieve this, the readme page has it owns section, but imho its kinda obsolete and not working

my recommended approach

is using the built in post_compile hooks from official heroku/python buildpacks
to do that add post_compile to your bin/ folder in your rails app

post_compile

set -e
buildpack_url=https://github.com/heroku/heroku-buildpack-python
buildpack_vsn=v197

# rebuild python if it's missing enable-shared
if  ! python3 -msysconfig | grep enable-shared \
    > /dev/null; then
  PYTHON_VERSION="$(< runtime.txt)"
  git clone -b "$buildpack_vsn" "$buildpack_url" _buildpack
  export WORKSPACE_DIR="$PWD/_buildpack/builds"
  rm -f .heroku/python/bin/python   # prevent failing ln after build
  sed -i 's!figure --pre!figure --enable-shared --pre!' \
    "$WORKSPACE_DIR"/runtimes/python3
  "$WORKSPACE_DIR/runtimes/$PYTHON_VERSION" /app/.heroku/python/
  rm -fr _buildpack
fi

with this when the heroku building your app for first time it will check did it have your required python runtime if not then they will install it but they will install it using pre-compile python that not use the --enable-shared options
after this first time script run then it will call the post_compile script

the post_compile script
will check if the installed python is have --enabled-shared config
if not the script will tell to remove the current installed python and compile the python runtime with --enabled-shared

after this your app could build smoothly

another approach

is to compile the python by urself with --enable-shared and upload the precompiled python somewhere then fork the official https://github.com/heroku/heroku-buildpack-python buildpacks and somehow make the scripts aim to download your precompiled python instead using heroku precompiled python

extra tips

if you want to check if your current python runtime has --enable-shared you could do run

heroku run bash then paste this
$ python3 -msysconfig | grep enable-shared
if there is --enable-shared then you good to go

another approach is in your bash open python
then from your python repl

import sysconfig
sysconfig.get_config_vars('Py_ENABLE_SHARED')

if it return [1] then its builded with --enable-shared

@buncis
Copy link
Contributor Author

buncis commented Jul 30, 2021

@mrkn thanks for this gem with this gem I could get the best of two worlds python pandas and numpy + ruby and rails

could we add this into wiki or readme.md?

but I think putting this on readme would be too much

@mrkn
Copy link
Owner

mrkn commented Feb 10, 2022

@buncis I'm sorry for my response to being late. PyCall's README already has the section that describes tips for deploying on Heroku. This section was added by the pull-request #134 on March 9, 2021. Did you check this part in README?

@mrkn mrkn added the question label Feb 10, 2022
@buncis
Copy link
Contributor Author

buncis commented Feb 10, 2022

@mrkn I have read that readme before, problem is I can't make my app work with that README

I think we could close this issue right now and could you enable discussion or wiki in this github repo?

so I could post my issue and guide to there?

@mrkn
Copy link
Owner

mrkn commented Feb 10, 2022

@buncis I don't want to open the wiki because the wiki is too difficult to keep managed. Opening the discussion can be acceptable, but I believe README is appropriate for mentioning the way to resolve this problem.

I want to know what information you needed is absent in the current README. Could you please tell me about it?

@buncis
Copy link
Contributor Author

buncis commented Feb 10, 2022 via email

@mrkn
Copy link
Owner

mrkn commented Feb 10, 2022

@buncis Thanks. I understand. It should be described in README and I want to do so. Could you please make a pull request to update the Heroku section in README?

@buncis
Copy link
Contributor Author

buncis commented Feb 10, 2022

I wish, but I can't do it right now, I'll do it later

@mrkn
Copy link
Owner

mrkn commented Feb 10, 2022

@buncis No problem. Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants