Async Rails 3.1 problem with assets - asynchronous

I have a problem with assets on an asynchronous rails 3.1 application, I managed to build a minimal example showing my problem but it did not helped me much.
The application is really simple, what I did was:
- create a fresh application with 3.1 (non rc)
- add thin+Rack::FiberPool
- setup bourbon (scss mixins)
- run the application
Now I start a server with "rails server thin", after that any request will end up in a "stack level too deep" with only one backtrace line :/
Here is the minimal application: https://github.com/schmurfy/assets_crash
Here is the backtrace I get when doing a request:
http://dl.dropbox.com/u/1313066/github/crash_assets.png
I tried to dig in to see where the problem was which led me in sass-rails in the file template_handlers.rb:
def sass_options(scope)
importer = self.importer(scope)
options = sass_options_from_rails(scope)
load_paths = (options[:load_paths] || []).dup
load_paths.unshift(importer)
# bnding.pry
options.merge(
:filename => eval_file,
:line => line,
:syntax => syntax,
:importer => importer,
:load_paths => load_paths,
:custom => {
:resolver => Resolver.new(scope)
}
)
end
I tried to explore with Pry (an irb alternative) and what I found is even more puzzling: While at the binding.pry line I can trigger a stack level too deep with:
{}.merge(:anything => Resolver.new(scope))
The result is immediate but I cannot find anything in that object which would explain the result.
Any lead would be welcome.

I finally found the answer: fibers only have 4Kb of stack space and Ruby on Rails is now too big to fit in this space :/

I had the same problem, upgraded my ruby to 1.9.3-preview1 and built all my gems from the ground up now everything works.
EDIT:
OK after playing with it a little more it really seems as if Rack::Fiberpool causes this issue. Got it back after I inserted Rack::Fiberpool back in my Rails stack...

Disable assets pipline in rails. Don't require sass-rails but instead require sass and sprockets in Gemfile. Here is my config.ru to serve assets:
require ::File.expand_path('../config/environment', __FILE__)
Sass::Engine::DEFAULT_OPTIONS[:load_paths].tap do |load_paths|
load_paths << "app/assets/stylesheets"
load_paths << Compass::Frameworks['compass'].stylesheets_directory
load_paths << Compass::Frameworks['twitter_bootstrap'].stylesheets_directory
end
builder = Rack::Builder.new do
map '/assets' do
environment = Sprockets::Environment.new
environment.append_path 'app/assets/javascripts'
environment.append_path 'app/assets/stylesheets'
run environment
end
map '/' do
use Rack::FiberPool, :size => 250
run YourApp::Application
end
end
run builder
It needs to precompile assets in production. I will look on it later.

Related

nginx module: compiles but fails to link a new library

I have modified an nginx module in a way that it depends on a library.... let's call the library that I need libx.
I have modified auto/os/linux in such a way that I am able to detect if libx is present... by adding something like:
+ngx_feature="libx"
+ngx_feature_name="NGX_HAVE_LIBX"
+ngx_feature_run=no
+ngx_feature_incs="#include <libx.h>"
+ngx_feature_path=
+ngx_feature_libs=-lx
+ngx_feature_test="libx_init();"
+. auto/feature
Then, in the module code I do #ifs checking for NGX_HAVE_LIBX... something like:
#if (NGX_HAVE_LIBX)
libx_init();
#endif
And it works like a charm.... when I run auto/configure I get that the library is detected with something like:
checking for libx... found
and it compiles BUT at link time it's not including -lx as part of the flags sent to cc/ld when building the final objs/nginx binary. I would have expected that after the feature be detected in auto/os/linux it would automagically be added to the linking phase when creating the Makefile... but apparently that's not the case so I know I am missing something... what additional step do I need to do to pull it off?
This is on nginx 1.19.2 (well, master branch from nginx mirror).
I think I got it.
I needed to add something like this:
+ngx_feature="libx"
+ngx_feature_name="NGX_HAVE_LIBX"
+ngx_feature_run=no
+ngx_feature_incs="#include <libx.h>"
+ngx_feature_path=
+ngx_feature_libs=-lx
+ngx_feature_test="libx_init();"
+. auto/feature
if [ $ngx_found = yes ]; then
CORE_LIBS="$CORE_LIBS -lx"
NGX_LIBDL="-lx"
fi

Define configuration with compiler plugin

I'd like to create a compile configuration which is the same as the default one but adds a compiler plugin. In my particular case, I want to have a "dev" configuration but with the linter plugin (https://github.com/HairyFotr/linter) because it slows down compile times and there's no need to run it in production or continuous integration.
Now this is what I tried:
lazy val Dev = config("dev") extend Compile
lazy val root = (project in file(".")).configs(Dev).settings(
inConfig(Dev)(addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.12")): _*)
and it should work, since when I inspect dev:libraryDependencies, it's what I expect it to be- it has org.psywerx.hairyfotr:linter:0.1.12:plugin->default(compile). Normally if I add the library with a "plugin" scope, it does work for the default settings:
libraryDependencies += ("org.psywerx.hairyfotr" %% "linter" % "0.1.12" % "plugin"
It just does not work if I add this under a different configuration, so there must be something else going on here.
This solves the problem, but not exactly in a way was asked. Here's the full build.sbt:
libraryDependencies ++= Seq(
"org.psywerx.hairyfotr" %% "linter" % "0.1.14" % "test")
val linter = Command.command("linter")(state => {
val linterJar = for {
(newState, result) <- Project.runTask(fullClasspath in Test, state)
cp <- result.toEither.right.toOption
linter <- cp.find(
_.get(moduleID.key).exists(mId =>
mId.organization == "org.psywerx.hairyfotr" &&
mId.name == "linter_2.11"))
} yield linter.data.absolutePath
val res = Project.runTask(scalacOptions, state)
res match {
case Some((newState, result)) =>
result.toEither.right.foreach { defaultScalacOptions =>
Project.runTask(compile in Test,
Project.extract(state).append(
scalacOptions := defaultScalacOptions ++ linterJar.map(p => Seq(s"-Xplugin:$p")).getOrElse(Seq.empty),
newState))
}
case None => sys.error("Couldn't get defaultScalacOptions")
}
state
})
lazy val root = (project in file(".")).configs(Test).settings(commands ++= Seq(linter))
The fact that you return unmodified state means you don't change the project settings. So if you run sbt linter, you should get your project compiled with the additional scalacOptions, but if you run compile in the same sbt session, it will not use those additional settings.
The tricky thing here is that scalacOptions is actually a TaskKey, not a SettingKey. I don't know why is that, but to get its value, you have to run that task. One reason might be that in sbt you cannot make setting depending on a task, but you can make a task depending on a task. In other words, scalacOptions can depend on the other task value, and maybe internally it does, I haven't checked. If current answer will work for you, I can try and think about more elegant way of achieving the same result.
EDIT: modified the code to specify the scalacOptions for the linter plugin proper. Please note the plugin has to be a managed dependency, not just a downloaded jar, for this solution to work. If you want to have it unmanaged, there's a way, but I won't go into it for now. Additionally, I've taken a freedom of making it also work for testing code, for illustration purposes.
Looking at Defaults.scala in the source, it seems like the compile command is always taking the options from the compile scope. So if I'm correct, you can have only one set of compilation options!
This seems to be confirmed by the fact that scalacOptions behaves the same way, and this is also why I don't see a non-hacky answer for these similar questions:
Different scalac options for different scopes or tasks?
Different compile options for tests and release in SBT?
I'd be happy to be proven wrong.
EDIT: FWIW, one might not be able to define another scalac options profile in the same project, but you could do so in a "different" project:
lazy val dev = (project in file(".")).
settings(target := baseDirectory.value / "target" / "dev").
settings(addCompilerPlugin("org.psywerx.hairyfotr" %% "linter" % "0.1.12"): _*)
This has the disadvantage that it has a separate output directory, so it will take more space and, more importantly, will not get incremental compiles between the two projects. However, after spending some time thinking about it, this may be by design. After all, even though linters don't, some scalac compilation options could conceivably change the output. This would make it meaningless to try to keep the metadata for incremental compilation from one set of scalac options to another. Thus different scalac options would indeed require different target directories.

Debugging bitbake pkg_postinst_${PN}: Append to config-file installed by other recipe

I'm writing am openembedded/bitbake recipe for openembedded-classic. My recipe RDEPENDS on keyutils, and everything seems to work, except one thing:
I want to append a single line to the /etc/request-key.conf file installed by the keyutils package. So I added the following to my recipe:
pkg_postinst_${PN} () {
echo 'create ... more stuff ..' >> ${sysconfdir}/request-key.conf
}
However, the intended added line is missing in my resulting image.
My recipe inherits update-rc.d if that makes any difference.
My main question is: How do i debug this? Currently I am constructing an entire rootfs image, and then poke-around in that to see, if the changes show up. Surely there is a better way?
UPDATE:
Changed recipe to:
pkg_postinst_${PN} () {
echo 'create ... more stuff ...' >> ${D}${sysconfdir}/request-key.conf
}
But still no luck.
As far as I know, postinst runs at rootfs creation, and only at first boot if rootfs fails.
So there is a easy way to execute something only first boot. Just check for $D, like this:
pkg_postinst_stuff() {
#!/bin/sh -e
if [ x"$D" = "x" ]; then
# do something at first boot here
else
exit 1
fi
}
postinst scripts are ran at roots time, so ${sysconfdir} is /etc on your host. Use $D${sysconfdir} to write to the file inside the rootfs being generated.
OE-Classic is pretty ancient so you really should update to oe-core.
That said, Do postinst's run at first boot? I'm not sure. Also look in the recipes work directory in the temp directory and read the log and run files to see if there are any clues there.
One more thing. If foo RDEPENDS on bar that just means "when foo is installed, bar is also installed". I'm not sure it makes assertions about what is installed during the install phase, when your postinst is running.
If using $D doesn't fix the problem try editing your postinst to copy the existing file you're trying to edit somewhere else, so you can verify that it exists in the first place. Its possible that you're appending to a file that doesn't exist yet, and the the package that installs the file replaces it.

Uploads not working properly NGINX + Passenger + Carrierwave + Carrierwave_backgrounder

I have a Rails 4.0.0 app setup with a model called episode which mounts a carrierwave uploader called file_uploader to upload mp3s. I got my app setup using carrierwave_backgrounder and resque to background the processing of the uploaded files which are saved to an sftp server using the carrierwave-ftp gem. On my local machine it works great. Also on my vps (CentOS 6) it works great when I just start up the app using rails s or even rails s -e production. However when I switch to nginx + passenger, it no longer works as expected.
The files are uploaded to the /public/uploads/tmp dir where they are supposed be stored temporarily, but they never get moved into the upload dir that I have specified and none of the other post-processing stuff gets done, like setting content type, removing cache dirs, setting file size and length, etc.
So, yesterday, I switched from using the carrierwave_backgrounder command save_in_background to process_in_background and now it works fine for files stored locally, however, when I switch to sftp storage using the carrierwave-ftp gem, the files get processed, i.e., they are transferred to my sftp server and the path is stored in my model, but then the job hangs in the Resque queue.
The relevant code that is not getting executed is:
process :set_content_type
process :save_content_type_duration_and_size_in_model
Does anyone have any idea why this would work fine using development mode and even production mode but not using nginx + passenger?
Here's all the relevant code below:
episode.rb:
class Episode < ActiveRecord::Base
require 'carrierwave/orm/activerecord'
# require 'mp3info'
mount_uploader :file, FileUploader
process_in_background :file
belongs_to :podcast
validates :name, :podcast, :file, presence: true
default_scope { order("created_at DESC") }
scope :most_recent, ->(max = 5) { limit(max) }
end
file_uploader.rb:
# encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base
include CarrierWave::MimeTypes
include ::CarrierWave::Backgrounder::Delay
storage :sftp
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"#{model.podcast.name.to_s.downcase.parameterize}"
end
before :store, :remember_cache_id
after :store, :delete_tmp_dir
# This is the relevant code that is not getting executed
process :set_content_type
process :save_content_type_duration_and_size_in_model
def save_content_type_duration_and_size_in_model
model.content_type = file.content_type if file.content_type
model.file_size = file.size
Mp3Info.open(model.file.current_path) do |media|
model.duration = media.length
end
end
# store! nil's the cache_id after it finishes so we need to remember it for deletion
def remember_cache_id(new_file)
#cache_id_was = cache_id
end
def delete_tmp_dir(new_file)
# make sure we don't delete other things accidentally by checking the name pattern
if #cache_id_was.present? && #cache_id_was =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
FileUtils.rm_rf(File.join(root, cache_dir, #cache_id_was))
end
end
end
config/initializers/carrierwave_backgrounder.rb:
CarrierWave::Backgrounder.configure do |c|
c.backend :resque, queue: :carrierwave
end
config/initializers/carrierwave.rb:
CarrierWave.configure do |config|
config.sftp_host = "ftphost.com"
config.sftp_user = "ftp_user"
config.sftp_folder = "ftp_password"
config.sftp_url = "http://url.com"
config.sftp_options = {
:password => "ftp_password",
:port => 22
}
end
I'm starting Resque with the command: QUEUE=* bundle exec rake environment resque:work &
If you need more info, just ask. Any help would be greatly appreciated.
UPDATE: Well, oddly enough as is often the case, it is now magically working. Not sure what did the trick, so I'm afraid this won't be of any help to anyone else who stumbles on this page.
i have the same issue. My process blocks run in development (rails s) but not under apache2/passenger. It's not pretty, but the way i solved it was to move my process code into the after :cache callback. The process blocks are called between the after and before cache callbacks so this seemed reasonable to me.
Here's the super weird part: I don't mean to call the functions, i mean to copy the code out of your process blocks (or functions) and paste directly into your after_cache callback.
I know i'm doing something wrong to cause this situation but i cannot figure it out. Hope this helps you.
version :office_preview
# comment out the following since it does nothing under Passenger
#process :office_to_img
end
def office_to_img
this won't be called under passenger :(
end
after :cache, :after_cache
def after_cache(file)
#for some reason, calling it here doesn't do anything
#office_to_img
code copied&pasted here from office_to_img
end

Issue loading rails 3 (server) after coming back from 3.1

total noob to rails and am using the Hartl tutorial.
Got to chapter 4 (CSS, 4.1.2), everything seemed dandy, and ran into an issue getting
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<%= csrf_meta_tag %>
<%= stylesheet_link_tag 'blueprint/screen', :media => 'screen' %>
<%= stylesheet_link_tag 'blueprint/print', :media => 'print' %>
</head>
<body>
<%= yield %>
</body>
</html>
to make the text on the page look 'prettier'. As Hartl describes it,
'By the way, with the new stylesheets the site doesn’t look much different than before, but it’s a start'
I do agree it looks cooler and this step is obviously more than necessary to continue.
So, nothing was changing on the localhost:3000/pages/home as it looked in chapter 3.
This is what it SHOULD look like
http://ruby.railstutorial.org/images/figures/home_with_stylesheet.png
(see attached pic^)
So I finally moved the stylesheets folder from public into app/assets/stylesheets, and added
this
<%= stylesheet_link_tag 'application.css' %>
to the application.html.erb file in app/views/layouts folder
Which I found from this portion of stackoverflow :) very helpful
So I fired up localhost:3000/pages/home and everything looked as it should (in relation to the png pic posted above) but all the text was centered, and it should be on the left side.
And, in addition, I was getting this message, repeated, in the terminal:
Started GET "/assets/stylesheets/src/typography.css?body=1" for 127.0.0.1 at 2012-01-04 17:34:13 -0800
Served asset /stylesheets/src/typography.css - 304 Not Modified (3ms)
[2012-01-04 17:34:13] WARN Could not determine content-length of response body. Set content- length of the response or set Response#chunked = true
So a buddy said it had to do with the rails version. We did share screen skype and he said in the home directory it should be 3.1 and in the sample_app directory it should be version 3.0.11 (he's a bit of a noob too but everything is going smoothly for him)
So alas I am back to getting the damn rails server to work. I'm on Snow Leopard and changed the sqlite3 thing, did bundle update then bundle install and worked fine. Now 'rails s' will not work ;/
the error message in the terminal is this:
/Users/davidpardy/rails_projects/sample_app/config/application.rb:8:in `require': no such file to load -- sprockets/railtie (LoadError)
from /Users/davidpardy/rails_projects/sample_app/config/application.rb:8:in '<top (required)>'
from /Users/davidpardy/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.11/lib/rails /commands.rb:28:in `require'
from /Users/davidpardy/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.11/lib/rails/commands.rb:28:in `block in <top (required)>'
from /Users/davidpardy/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.11/lib/rails/commands.rb:27:in `tap'
from /Users/davidpardy/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.11/lib/rails/commands.rb:27:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
So now I'm stuck and really don't know what to do. Don't want to start from scratch.
Like I said I'm new to this so any input would be appreciated. This seems like a rather easy fix, just lost.
im in the same boat as you, i am running rails 3.1.3 and am not in the mood atm to start over for a lower rails (or to figure out how to seamlessly change rails version).
i decided to remove the blueprint folder and its two including lines in application.html.erb, and make a new inclusion of a custom css file i put directly in app/assets/stylesheets. the css was just to make the background red, and thats what it did. not sure why our pages were being centered like that using the blueprint, but it looks okay now. as mentioned earlier, the safest bet is to just use the same versions as the tutorials, or 3.0.11 for rails as mr. hartl has indicated in a comment.
Per the answer to Trouble loading Rails Server (3.0.11, ruby 1.9.2), no such file to load -- sprockets/railtie (LoadError), you should remote Rails 3.1-specific lines from auto-generated files, mostly in config/.
One way to figure out what lines to remove is to compare your app to a fresh Rails 3.0 app using diff -r
Step 1: Create a clean Rails 3.0 app
$ rails --version
Rails 3.0.10
$ rails new fresh_app
create
create README
create Rakefile
Step 2: Use diff -r to compare the directories
$ diff -r hartl_tutorial/config fresh_app/config
diff -r hartl_tutorial/config/application.rb fresh_app/config/application.rb
5,10c5,7
< if defined?(Bundler)
< # If you precompile assets before deploying to production, use this line
< Bundler.require(*Rails.groups(:assets => %w(development test)))
< # If you want your assets lazily compiled in production, use this line
< # Bundler.require(:default, :assets, Rails.env)
< end
---
> # If you have a Gemfile, require the gems listed there, including any gems
> # you've limited to :test, :development, or :production.
> Bundler.require(:default, Rails.env) if defined?(Bundler)
In case you don't know how to read a diff, the basic idea is that lines starting with < are from one file while lines starting with > are from the other file.

Resources